18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * i.MX6 Video Data Order Adapter (VDOA) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Philipp Zabel 68c2ecf20Sopenharmony_ci * Copyright (C) 2016 Pengutronix, Michael Tretter <kernel@pengutronix.de> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 148c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "imx-vdoa.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define VDOA_NAME "imx-vdoa" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define VDOAC 0x00 248c2ecf20Sopenharmony_ci#define VDOASRR 0x04 258c2ecf20Sopenharmony_ci#define VDOAIE 0x08 268c2ecf20Sopenharmony_ci#define VDOAIST 0x0c 278c2ecf20Sopenharmony_ci#define VDOAFP 0x10 288c2ecf20Sopenharmony_ci#define VDOAIEBA00 0x14 298c2ecf20Sopenharmony_ci#define VDOAIEBA01 0x18 308c2ecf20Sopenharmony_ci#define VDOAIEBA02 0x1c 318c2ecf20Sopenharmony_ci#define VDOAIEBA10 0x20 328c2ecf20Sopenharmony_ci#define VDOAIEBA11 0x24 338c2ecf20Sopenharmony_ci#define VDOAIEBA12 0x28 348c2ecf20Sopenharmony_ci#define VDOASL 0x2c 358c2ecf20Sopenharmony_ci#define VDOAIUBO 0x30 368c2ecf20Sopenharmony_ci#define VDOAVEBA0 0x34 378c2ecf20Sopenharmony_ci#define VDOAVEBA1 0x38 388c2ecf20Sopenharmony_ci#define VDOAVEBA2 0x3c 398c2ecf20Sopenharmony_ci#define VDOAVUBO 0x40 408c2ecf20Sopenharmony_ci#define VDOASR 0x44 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define VDOAC_ISEL BIT(6) 438c2ecf20Sopenharmony_ci#define VDOAC_PFS BIT(5) 448c2ecf20Sopenharmony_ci#define VDOAC_SO BIT(4) 458c2ecf20Sopenharmony_ci#define VDOAC_SYNC BIT(3) 468c2ecf20Sopenharmony_ci#define VDOAC_NF BIT(2) 478c2ecf20Sopenharmony_ci#define VDOAC_BNDM_MASK 0x3 488c2ecf20Sopenharmony_ci#define VDOAC_BAND_HEIGHT_8 0x0 498c2ecf20Sopenharmony_ci#define VDOAC_BAND_HEIGHT_16 0x1 508c2ecf20Sopenharmony_ci#define VDOAC_BAND_HEIGHT_32 0x2 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define VDOASRR_START BIT(1) 538c2ecf20Sopenharmony_ci#define VDOASRR_SWRST BIT(0) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define VDOAIE_EITERR BIT(1) 568c2ecf20Sopenharmony_ci#define VDOAIE_EIEOT BIT(0) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define VDOAIST_TERR BIT(1) 598c2ecf20Sopenharmony_ci#define VDOAIST_EOT BIT(0) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define VDOAFP_FH_MASK (0x1fff << 16) 628c2ecf20Sopenharmony_ci#define VDOAFP_FW_MASK (0x3fff) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define VDOASL_VSLY_MASK (0x3fff << 16) 658c2ecf20Sopenharmony_ci#define VDOASL_ISLY_MASK (0x7fff) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define VDOASR_ERRW BIT(4) 688c2ecf20Sopenharmony_ci#define VDOASR_EOB BIT(3) 698c2ecf20Sopenharmony_ci#define VDOASR_CURRENT_FRAME (0x3 << 1) 708c2ecf20Sopenharmony_ci#define VDOASR_CURRENT_BUFFER BIT(1) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cienum { 738c2ecf20Sopenharmony_ci V4L2_M2M_SRC = 0, 748c2ecf20Sopenharmony_ci V4L2_M2M_DST = 1, 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct vdoa_data { 788c2ecf20Sopenharmony_ci struct vdoa_ctx *curr_ctx; 798c2ecf20Sopenharmony_ci struct device *dev; 808c2ecf20Sopenharmony_ci struct clk *vdoa_clk; 818c2ecf20Sopenharmony_ci void __iomem *regs; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct vdoa_q_data { 858c2ecf20Sopenharmony_ci unsigned int width; 868c2ecf20Sopenharmony_ci unsigned int height; 878c2ecf20Sopenharmony_ci unsigned int bytesperline; 888c2ecf20Sopenharmony_ci unsigned int sizeimage; 898c2ecf20Sopenharmony_ci u32 pixelformat; 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistruct vdoa_ctx { 938c2ecf20Sopenharmony_ci struct vdoa_data *vdoa; 948c2ecf20Sopenharmony_ci struct completion completion; 958c2ecf20Sopenharmony_ci struct vdoa_q_data q_data[2]; 968c2ecf20Sopenharmony_ci unsigned int submitted_job; 978c2ecf20Sopenharmony_ci unsigned int completed_job; 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic irqreturn_t vdoa_irq_handler(int irq, void *data) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct vdoa_data *vdoa = data; 1038c2ecf20Sopenharmony_ci struct vdoa_ctx *curr_ctx; 1048c2ecf20Sopenharmony_ci u32 val; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* Disable interrupts */ 1078c2ecf20Sopenharmony_ci writel(0, vdoa->regs + VDOAIE); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci curr_ctx = vdoa->curr_ctx; 1108c2ecf20Sopenharmony_ci if (!curr_ctx) { 1118c2ecf20Sopenharmony_ci dev_warn(vdoa->dev, 1128c2ecf20Sopenharmony_ci "Instance released before the end of transaction\n"); 1138c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci val = readl(vdoa->regs + VDOAIST); 1178c2ecf20Sopenharmony_ci writel(val, vdoa->regs + VDOAIST); 1188c2ecf20Sopenharmony_ci if (val & VDOAIST_TERR) { 1198c2ecf20Sopenharmony_ci val = readl(vdoa->regs + VDOASR) & VDOASR_ERRW; 1208c2ecf20Sopenharmony_ci dev_err(vdoa->dev, "AXI %s error\n", val ? "write" : "read"); 1218c2ecf20Sopenharmony_ci } else if (!(val & VDOAIST_EOT)) { 1228c2ecf20Sopenharmony_ci dev_warn(vdoa->dev, "Spurious interrupt\n"); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci curr_ctx->completed_job++; 1258c2ecf20Sopenharmony_ci complete(&curr_ctx->completion); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ciint vdoa_wait_for_completion(struct vdoa_ctx *ctx) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct vdoa_data *vdoa = ctx->vdoa; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (ctx->submitted_job == ctx->completed_job) 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&ctx->completion, 1388c2ecf20Sopenharmony_ci msecs_to_jiffies(300))) { 1398c2ecf20Sopenharmony_ci dev_err(vdoa->dev, 1408c2ecf20Sopenharmony_ci "Timeout waiting for transfer result\n"); 1418c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vdoa_wait_for_completion); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_civoid vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct vdoa_q_data *src_q_data, *dst_q_data; 1518c2ecf20Sopenharmony_ci struct vdoa_data *vdoa = ctx->vdoa; 1528c2ecf20Sopenharmony_ci u32 val; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (vdoa->curr_ctx) 1558c2ecf20Sopenharmony_ci vdoa_wait_for_completion(vdoa->curr_ctx); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci vdoa->curr_ctx = ctx; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci reinit_completion(&ctx->completion); 1608c2ecf20Sopenharmony_ci ctx->submitted_job++; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci src_q_data = &ctx->q_data[V4L2_M2M_SRC]; 1638c2ecf20Sopenharmony_ci dst_q_data = &ctx->q_data[V4L2_M2M_DST]; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Progressive, no sync, 1 frame per run */ 1668c2ecf20Sopenharmony_ci if (dst_q_data->pixelformat == V4L2_PIX_FMT_YUYV) 1678c2ecf20Sopenharmony_ci val = VDOAC_PFS; 1688c2ecf20Sopenharmony_ci else 1698c2ecf20Sopenharmony_ci val = 0; 1708c2ecf20Sopenharmony_ci writel(val, vdoa->regs + VDOAC); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci writel(dst_q_data->height << 16 | dst_q_data->width, 1738c2ecf20Sopenharmony_ci vdoa->regs + VDOAFP); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci val = dst; 1768c2ecf20Sopenharmony_ci writel(val, vdoa->regs + VDOAIEBA00); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci writel(src_q_data->bytesperline << 16 | dst_q_data->bytesperline, 1798c2ecf20Sopenharmony_ci vdoa->regs + VDOASL); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (dst_q_data->pixelformat == V4L2_PIX_FMT_NV12 || 1828c2ecf20Sopenharmony_ci dst_q_data->pixelformat == V4L2_PIX_FMT_NV21) 1838c2ecf20Sopenharmony_ci val = dst_q_data->bytesperline * dst_q_data->height; 1848c2ecf20Sopenharmony_ci else 1858c2ecf20Sopenharmony_ci val = 0; 1868c2ecf20Sopenharmony_ci writel(val, vdoa->regs + VDOAIUBO); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci val = src; 1898c2ecf20Sopenharmony_ci writel(val, vdoa->regs + VDOAVEBA0); 1908c2ecf20Sopenharmony_ci val = round_up(src_q_data->bytesperline * src_q_data->height, 4096); 1918c2ecf20Sopenharmony_ci writel(val, vdoa->regs + VDOAVUBO); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Enable interrupts and start transfer */ 1948c2ecf20Sopenharmony_ci writel(VDOAIE_EITERR | VDOAIE_EIEOT, vdoa->regs + VDOAIE); 1958c2ecf20Sopenharmony_ci writel(VDOASRR_START, vdoa->regs + VDOASRR); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vdoa_device_run); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistruct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct vdoa_ctx *ctx; 2028c2ecf20Sopenharmony_ci int err; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 2058c2ecf20Sopenharmony_ci if (!ctx) 2068c2ecf20Sopenharmony_ci return NULL; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci err = clk_prepare_enable(vdoa->vdoa_clk); 2098c2ecf20Sopenharmony_ci if (err) { 2108c2ecf20Sopenharmony_ci kfree(ctx); 2118c2ecf20Sopenharmony_ci return NULL; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci init_completion(&ctx->completion); 2158c2ecf20Sopenharmony_ci ctx->vdoa = vdoa; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return ctx; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vdoa_context_create); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_civoid vdoa_context_destroy(struct vdoa_ctx *ctx) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct vdoa_data *vdoa = ctx->vdoa; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (vdoa->curr_ctx == ctx) { 2268c2ecf20Sopenharmony_ci vdoa_wait_for_completion(vdoa->curr_ctx); 2278c2ecf20Sopenharmony_ci vdoa->curr_ctx = NULL; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci clk_disable_unprepare(vdoa->vdoa_clk); 2318c2ecf20Sopenharmony_ci kfree(ctx); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vdoa_context_destroy); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ciint vdoa_context_configure(struct vdoa_ctx *ctx, 2368c2ecf20Sopenharmony_ci unsigned int width, unsigned int height, 2378c2ecf20Sopenharmony_ci u32 pixelformat) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct vdoa_q_data *src_q_data; 2408c2ecf20Sopenharmony_ci struct vdoa_q_data *dst_q_data; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (width < 16 || width > 8192 || width % 16 != 0 || 2438c2ecf20Sopenharmony_ci height < 16 || height > 4096 || height % 16 != 0) 2448c2ecf20Sopenharmony_ci return -EINVAL; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (pixelformat != V4L2_PIX_FMT_YUYV && 2478c2ecf20Sopenharmony_ci pixelformat != V4L2_PIX_FMT_NV12) 2488c2ecf20Sopenharmony_ci return -EINVAL; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* If no context is passed, only check if the format is valid */ 2518c2ecf20Sopenharmony_ci if (!ctx) 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci src_q_data = &ctx->q_data[V4L2_M2M_SRC]; 2558c2ecf20Sopenharmony_ci dst_q_data = &ctx->q_data[V4L2_M2M_DST]; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci src_q_data->width = width; 2588c2ecf20Sopenharmony_ci src_q_data->height = height; 2598c2ecf20Sopenharmony_ci src_q_data->bytesperline = width; 2608c2ecf20Sopenharmony_ci src_q_data->sizeimage = 2618c2ecf20Sopenharmony_ci round_up(src_q_data->bytesperline * height, 4096) + 2628c2ecf20Sopenharmony_ci src_q_data->bytesperline * height / 2; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci dst_q_data->width = width; 2658c2ecf20Sopenharmony_ci dst_q_data->height = height; 2668c2ecf20Sopenharmony_ci dst_q_data->pixelformat = pixelformat; 2678c2ecf20Sopenharmony_ci switch (pixelformat) { 2688c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 2698c2ecf20Sopenharmony_ci dst_q_data->bytesperline = width * 2; 2708c2ecf20Sopenharmony_ci dst_q_data->sizeimage = dst_q_data->bytesperline * height; 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV12: 2738c2ecf20Sopenharmony_ci default: 2748c2ecf20Sopenharmony_ci dst_q_data->bytesperline = width; 2758c2ecf20Sopenharmony_ci dst_q_data->sizeimage = 2768c2ecf20Sopenharmony_ci dst_q_data->bytesperline * height * 3 / 2; 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return 0; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vdoa_context_configure); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int vdoa_probe(struct platform_device *pdev) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct vdoa_data *vdoa; 2878c2ecf20Sopenharmony_ci struct resource *res; 2888c2ecf20Sopenharmony_ci int ret; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 2918c2ecf20Sopenharmony_ci if (ret) { 2928c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "DMA enable failed\n"); 2938c2ecf20Sopenharmony_ci return ret; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci vdoa = devm_kzalloc(&pdev->dev, sizeof(*vdoa), GFP_KERNEL); 2978c2ecf20Sopenharmony_ci if (!vdoa) 2988c2ecf20Sopenharmony_ci return -ENOMEM; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci vdoa->dev = &pdev->dev; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci vdoa->vdoa_clk = devm_clk_get(vdoa->dev, NULL); 3038c2ecf20Sopenharmony_ci if (IS_ERR(vdoa->vdoa_clk)) { 3048c2ecf20Sopenharmony_ci dev_err(vdoa->dev, "Failed to get clock\n"); 3058c2ecf20Sopenharmony_ci return PTR_ERR(vdoa->vdoa_clk); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3098c2ecf20Sopenharmony_ci vdoa->regs = devm_ioremap_resource(vdoa->dev, res); 3108c2ecf20Sopenharmony_ci if (IS_ERR(vdoa->regs)) 3118c2ecf20Sopenharmony_ci return PTR_ERR(vdoa->regs); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 3148c2ecf20Sopenharmony_ci if (!res) 3158c2ecf20Sopenharmony_ci return -EINVAL; 3168c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, res->start, NULL, 3178c2ecf20Sopenharmony_ci vdoa_irq_handler, IRQF_ONESHOT, 3188c2ecf20Sopenharmony_ci "vdoa", vdoa); 3198c2ecf20Sopenharmony_ci if (ret < 0) { 3208c2ecf20Sopenharmony_ci dev_err(vdoa->dev, "Failed to get irq\n"); 3218c2ecf20Sopenharmony_ci return ret; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, vdoa); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int vdoa_remove(struct platform_device *pdev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic const struct of_device_id vdoa_dt_ids[] = { 3358c2ecf20Sopenharmony_ci { .compatible = "fsl,imx6q-vdoa" }, 3368c2ecf20Sopenharmony_ci {} 3378c2ecf20Sopenharmony_ci}; 3388c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, vdoa_dt_ids); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic struct platform_driver vdoa_driver = { 3418c2ecf20Sopenharmony_ci .probe = vdoa_probe, 3428c2ecf20Sopenharmony_ci .remove = vdoa_remove, 3438c2ecf20Sopenharmony_ci .driver = { 3448c2ecf20Sopenharmony_ci .name = VDOA_NAME, 3458c2ecf20Sopenharmony_ci .of_match_table = vdoa_dt_ids, 3468c2ecf20Sopenharmony_ci }, 3478c2ecf20Sopenharmony_ci}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cimodule_platform_driver(vdoa_driver); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Video Data Order Adapter"); 3528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>"); 3538c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:imx-vdoa"); 3548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 355