]> rtime.felk.cvut.cz Git - zynq/linux.git/blob - drivers/media/platform/xilinx/xilinx-scenechange.c
v4l: xilinx: scd: Clean up #include statements
[zynq/linux.git] / drivers / media / platform / xilinx / xilinx-scenechange.c
1 //SPDX-License-Identifier: GPL-2.0
2 /*
3  * Xilinx Scene Change Detection driver
4  *
5  * Copyright (C) 2018 Xilinx, Inc.
6  *
7  * Authors: Anand Ashok Dumbre <anand.ashok.dumbre@xilinx.com>
8  *          Satish Kumar Nagireddy <satish.nagireddy.nagireddy@xilinx.com>
9  */
10
11 #include <linux/clk.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/interrupt.h>
14 #include <linux/module.h>
15 #include <linux/of.h>
16 #include <linux/platform_device.h>
17
18 #include "xilinx-scenechange.h"
19
20 #define XSCD_RESET_DEASSERT     (0)
21 #define XSCD_RESET_ASSERT       (1)
22
23 static irqreturn_t xscd_irq_handler(int irq, void *data)
24 {
25         struct xscd_device *xscd = (struct xscd_device *)data;
26         unsigned int i;
27         u32 status;
28
29         status = xscd_read(xscd->iomem, XSCD_ISR_OFFSET);
30         if (!(status & XSCD_IE_AP_DONE))
31                 return IRQ_NONE;
32
33         xscd_write(xscd->iomem, XSCD_ISR_OFFSET, XSCD_IE_AP_DONE);
34
35         for (i = 0; i < xscd->num_streams; ++i)
36                 xscd_chan_irq_handler(&xscd->chans[i]);
37
38         xscd_dma_irq_handler(xscd);
39
40         return IRQ_HANDLED;
41 }
42
43 static int xscd_init_resources(struct xscd_device *xscd)
44 {
45         struct platform_device *pdev = to_platform_device(xscd->dev);
46         struct resource *res;
47
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);
52
53         xscd->irq = platform_get_irq(pdev, 0);
54         if (xscd->irq < 0) {
55                 dev_err(xscd->dev, "No valid irq found\n");
56                 return -EINVAL;
57         }
58
59         xscd->clk = devm_clk_get(xscd->dev, NULL);
60         if (IS_ERR(xscd->clk))
61                 return PTR_ERR(xscd->clk);
62
63         clk_prepare_enable(xscd->clk);
64         return 0;
65 }
66
67 static int xscd_parse_of(struct xscd_device *xscd)
68 {
69         struct device *dev = xscd->dev;
70         struct device_node *node = xscd->dev->of_node;
71         int ret;
72
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");
78
79                 return PTR_ERR(xscd->rst_gpio);
80         }
81
82         ret = of_property_read_u32(node, "xlnx,numstreams",
83                                    &xscd->num_streams);
84         if (ret < 0)
85                 return ret;
86
87         if (!xscd->memory_based && xscd->num_streams != 1) {
88                 dev_err(dev, "Stream-based mode only supports one stream\n");
89                 return -EINVAL;
90         }
91
92         return 0;
93 }
94
95 static int xscd_probe(struct platform_device *pdev)
96 {
97         struct xscd_device *xscd;
98         struct device_node *subdev_node;
99         unsigned int id;
100         int ret;
101
102         xscd = devm_kzalloc(&pdev->dev, sizeof(*xscd), GFP_KERNEL);
103         if (!xscd)
104                 return -ENOMEM;
105
106         xscd->dev = &pdev->dev;
107         platform_set_drvdata(pdev, xscd);
108
109         ret = xscd_parse_of(xscd);
110         if (ret < 0)
111                 return ret;
112
113         ret = xscd_init_resources(xscd);
114         if (ret < 0)
115                 return ret;
116
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);
120
121         /* Initialize the channels. */
122         xscd->chans = devm_kcalloc(xscd->dev, xscd->num_streams,
123                                    sizeof(*xscd->chans), GFP_KERNEL);
124         if (!xscd->chans)
125                 return -ENOMEM;
126
127         id = 0;
128         for_each_child_of_node(xscd->dev->of_node, subdev_node) {
129                 if (id >= xscd->num_streams) {
130                         dev_warn(&pdev->dev,
131                                  "Too many channels, limiting to %u\n",
132                                  xscd->num_streams);
133                         of_node_put(subdev_node);
134                         break;
135                 }
136
137                 ret = xscd_chan_init(xscd, id, subdev_node);
138                 if (ret < 0) {
139                         dev_err(&pdev->dev, "Failed to initialize channel %u\n",
140                                 id);
141                         return ret;
142                 }
143
144                 id++;
145         }
146
147         /* Initialize the DMA engine. */
148         ret = xscd_dma_init(xscd);
149         if (ret < 0)
150                 dev_err(&pdev->dev, "Failed to initialize the DMA\n");
151
152         ret = devm_request_irq(xscd->dev, xscd->irq, xscd_irq_handler,
153                                IRQF_SHARED, dev_name(xscd->dev), xscd);
154         if (ret < 0)
155                 dev_err(&pdev->dev, "Failed to request IRQ\n");
156
157         dev_info(xscd->dev, "scene change detect device found!\n");
158         return 0;
159 }
160
161 static int xscd_remove(struct platform_device *pdev)
162 {
163         struct xscd_device *xscd = platform_get_drvdata(pdev);
164
165         xscd_dma_cleanup(xscd);
166         clk_disable_unprepare(xscd->clk);
167
168         return 0;
169 }
170
171 static const struct of_device_id xscd_of_id_table[] = {
172         { .compatible = "xlnx,v-scd" },
173         { }
174 };
175 MODULE_DEVICE_TABLE(of, xscd_of_id_table);
176
177 static struct platform_driver xscd_driver = {
178         .driver = {
179                 .name           = "xilinx-scd",
180                 .of_match_table = xscd_of_id_table,
181         },
182         .probe                  = xscd_probe,
183         .remove                 = xscd_remove,
184 };
185
186 module_platform_driver(xscd_driver);
187
188 MODULE_AUTHOR("Xilinx Inc.");
189 MODULE_DESCRIPTION("Xilinx Scene Change Detection");
190 MODULE_LICENSE("GPL v2");