1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 208302c35SEric Anholt /* 308302c35SEric Anholt * Copyright (C) 2016 Broadcom Limited 408302c35SEric Anholt */ 508302c35SEric Anholt 608302c35SEric Anholt /** 708302c35SEric Anholt * DOC: VC4 DPI module 808302c35SEric Anholt * 908302c35SEric Anholt * The VC4 DPI hardware supports MIPI DPI type 4 and Nokia ViSSI 10f6c01530SEric Anholt * signals. On BCM2835, these can be routed out to GPIO0-27 with the 11f6c01530SEric Anholt * ALT2 function. 1208302c35SEric Anholt */ 1308302c35SEric Anholt 14b7e8e25bSMasahiro Yamada #include <drm/drm_atomic_helper.h> 157b1298e0SEric Anholt #include <drm/drm_bridge.h> 16b7e8e25bSMasahiro Yamada #include <drm/drm_edid.h> 177b1298e0SEric Anholt #include <drm/drm_of.h> 18b7e8e25bSMasahiro Yamada #include <drm/drm_panel.h> 19fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h> 20f6ebc1b0SThomas Zimmermann #include <drm/drm_simple_kms_helper.h> 21b7e8e25bSMasahiro Yamada #include <linux/clk.h> 22b7e8e25bSMasahiro Yamada #include <linux/component.h> 23*72bd9ea3SVille Syrjälä #include <linux/media-bus-format.h> 24b7e8e25bSMasahiro Yamada #include <linux/of_graph.h> 25b7e8e25bSMasahiro Yamada #include <linux/of_platform.h> 2608302c35SEric Anholt #include "vc4_drv.h" 2708302c35SEric Anholt #include "vc4_regs.h" 2808302c35SEric Anholt 2908302c35SEric Anholt #define DPI_C 0x00 3008302c35SEric Anholt # define DPI_OUTPUT_ENABLE_MODE BIT(16) 3108302c35SEric Anholt 3208302c35SEric Anholt /* The order field takes the incoming 24 bit RGB from the pixel valve 3308302c35SEric Anholt * and shuffles the 3 channels. 3408302c35SEric Anholt */ 3508302c35SEric Anholt # define DPI_ORDER_MASK VC4_MASK(15, 14) 3608302c35SEric Anholt # define DPI_ORDER_SHIFT 14 3708302c35SEric Anholt # define DPI_ORDER_RGB 0 3808302c35SEric Anholt # define DPI_ORDER_BGR 1 3908302c35SEric Anholt # define DPI_ORDER_GRB 2 4008302c35SEric Anholt # define DPI_ORDER_BRG 3 4108302c35SEric Anholt 4208302c35SEric Anholt /* The format field takes the ORDER-shuffled pixel valve data and 4308302c35SEric Anholt * formats it onto the output lines. 4408302c35SEric Anholt */ 4508302c35SEric Anholt # define DPI_FORMAT_MASK VC4_MASK(13, 11) 4608302c35SEric Anholt # define DPI_FORMAT_SHIFT 11 4708302c35SEric Anholt /* This define is named in the hardware, but actually just outputs 0. */ 4808302c35SEric Anholt # define DPI_FORMAT_9BIT_666_RGB 0 4908302c35SEric Anholt /* Outputs 00000000rrrrrggggggbbbbb */ 5008302c35SEric Anholt # define DPI_FORMAT_16BIT_565_RGB_1 1 5108302c35SEric Anholt /* Outputs 000rrrrr00gggggg000bbbbb */ 5208302c35SEric Anholt # define DPI_FORMAT_16BIT_565_RGB_2 2 5308302c35SEric Anholt /* Outputs 00rrrrr000gggggg00bbbbb0 */ 5408302c35SEric Anholt # define DPI_FORMAT_16BIT_565_RGB_3 3 5508302c35SEric Anholt /* Outputs 000000rrrrrrggggggbbbbbb */ 5608302c35SEric Anholt # define DPI_FORMAT_18BIT_666_RGB_1 4 5708302c35SEric Anholt /* Outputs 00rrrrrr00gggggg00bbbbbb */ 5808302c35SEric Anholt # define DPI_FORMAT_18BIT_666_RGB_2 5 5908302c35SEric Anholt /* Outputs rrrrrrrrggggggggbbbbbbbb */ 6008302c35SEric Anholt # define DPI_FORMAT_24BIT_888_RGB 6 6108302c35SEric Anholt 6208302c35SEric Anholt /* Reverses the polarity of the corresponding signal */ 6308302c35SEric Anholt # define DPI_PIXEL_CLK_INVERT BIT(10) 6408302c35SEric Anholt # define DPI_HSYNC_INVERT BIT(9) 6508302c35SEric Anholt # define DPI_VSYNC_INVERT BIT(8) 6608302c35SEric Anholt # define DPI_OUTPUT_ENABLE_INVERT BIT(7) 6708302c35SEric Anholt 6808302c35SEric Anholt /* Outputs the signal the falling clock edge instead of rising. */ 6908302c35SEric Anholt # define DPI_HSYNC_NEGATE BIT(6) 7008302c35SEric Anholt # define DPI_VSYNC_NEGATE BIT(5) 7108302c35SEric Anholt # define DPI_OUTPUT_ENABLE_NEGATE BIT(4) 7208302c35SEric Anholt 7308302c35SEric Anholt /* Disables the signal */ 7408302c35SEric Anholt # define DPI_HSYNC_DISABLE BIT(3) 7508302c35SEric Anholt # define DPI_VSYNC_DISABLE BIT(2) 7608302c35SEric Anholt # define DPI_OUTPUT_ENABLE_DISABLE BIT(1) 7708302c35SEric Anholt 7808302c35SEric Anholt /* Power gate to the device, full reset at 0 -> 1 transition */ 7908302c35SEric Anholt # define DPI_ENABLE BIT(0) 8008302c35SEric Anholt 8108302c35SEric Anholt /* All other registers besides DPI_C return the ID */ 8208302c35SEric Anholt #define DPI_ID 0x04 8308302c35SEric Anholt # define DPI_ID_VALUE 0x00647069 8408302c35SEric Anholt 8508302c35SEric Anholt /* General DPI hardware state. */ 8608302c35SEric Anholt struct vc4_dpi { 8708302c35SEric Anholt struct platform_device *pdev; 8808302c35SEric Anholt 8908302c35SEric Anholt struct drm_encoder *encoder; 9008302c35SEric Anholt 9108302c35SEric Anholt void __iomem *regs; 9208302c35SEric Anholt 9308302c35SEric Anholt struct clk *pixel_clock; 9408302c35SEric Anholt struct clk *core_clock; 953051719aSEric Anholt 963051719aSEric Anholt struct debugfs_regset32 regset; 9708302c35SEric Anholt }; 9808302c35SEric Anholt 9908302c35SEric Anholt #define DPI_READ(offset) readl(dpi->regs + (offset)) 10008302c35SEric Anholt #define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset)) 10108302c35SEric Anholt 10208302c35SEric Anholt /* VC4 DPI encoder KMS struct */ 10308302c35SEric Anholt struct vc4_dpi_encoder { 10408302c35SEric Anholt struct vc4_encoder base; 10508302c35SEric Anholt struct vc4_dpi *dpi; 10608302c35SEric Anholt }; 10708302c35SEric Anholt 10808302c35SEric Anholt static inline struct vc4_dpi_encoder * 10908302c35SEric Anholt to_vc4_dpi_encoder(struct drm_encoder *encoder) 11008302c35SEric Anholt { 11108302c35SEric Anholt return container_of(encoder, struct vc4_dpi_encoder, base.base); 11208302c35SEric Anholt } 11308302c35SEric Anholt 1143051719aSEric Anholt static const struct debugfs_reg32 dpi_regs[] = { 1153051719aSEric Anholt VC4_REG32(DPI_C), 1163051719aSEric Anholt VC4_REG32(DPI_ID), 11708302c35SEric Anholt }; 11808302c35SEric Anholt 11908302c35SEric Anholt static void vc4_dpi_encoder_disable(struct drm_encoder *encoder) 12008302c35SEric Anholt { 12108302c35SEric Anholt struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder); 12208302c35SEric Anholt struct vc4_dpi *dpi = vc4_encoder->dpi; 12308302c35SEric Anholt 12408302c35SEric Anholt clk_disable_unprepare(dpi->pixel_clock); 12508302c35SEric Anholt } 12608302c35SEric Anholt 12708302c35SEric Anholt static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) 12808302c35SEric Anholt { 129164c2416SEric Anholt struct drm_device *dev = encoder->dev; 13008302c35SEric Anholt struct drm_display_mode *mode = &encoder->crtc->mode; 13108302c35SEric Anholt struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder); 13208302c35SEric Anholt struct vc4_dpi *dpi = vc4_encoder->dpi; 133164c2416SEric Anholt struct drm_connector_list_iter conn_iter; 134164c2416SEric Anholt struct drm_connector *connector = NULL, *connector_scan; 1357fea3c23SDave Stevenson u32 dpi_c = DPI_ENABLE; 13608302c35SEric Anholt int ret; 13708302c35SEric Anholt 138164c2416SEric Anholt /* Look up the connector attached to DPI so we can get the 139164c2416SEric Anholt * bus_format. Ideally the bridge would tell us the 140164c2416SEric Anholt * bus_format we want, but it doesn't yet, so assume that it's 141164c2416SEric Anholt * uniform throughout the bridge chain. 142164c2416SEric Anholt */ 143164c2416SEric Anholt drm_connector_list_iter_begin(dev, &conn_iter); 144164c2416SEric Anholt drm_for_each_connector_iter(connector_scan, &conn_iter) { 145164c2416SEric Anholt if (connector_scan->encoder == encoder) { 146164c2416SEric Anholt connector = connector_scan; 147164c2416SEric Anholt break; 148164c2416SEric Anholt } 149164c2416SEric Anholt } 150164c2416SEric Anholt drm_connector_list_iter_end(&conn_iter); 151164c2416SEric Anholt 1527a70b0b9SDave Stevenson /* Default to 24bit if no connector or format found. */ 1537a70b0b9SDave Stevenson dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, DPI_FORMAT); 1547a70b0b9SDave Stevenson 1553c270763SDave Stevenson if (connector) { 1563c270763SDave Stevenson if (connector->display_info.num_bus_formats) { 157164c2416SEric Anholt u32 bus_format = connector->display_info.bus_formats[0]; 15808302c35SEric Anholt 1597a70b0b9SDave Stevenson dpi_c &= ~DPI_FORMAT_MASK; 1607a70b0b9SDave Stevenson 16108302c35SEric Anholt switch (bus_format) { 16208302c35SEric Anholt case MEDIA_BUS_FMT_RGB888_1X24: 16308302c35SEric Anholt dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, 16408302c35SEric Anholt DPI_FORMAT); 16508302c35SEric Anholt break; 16608302c35SEric Anholt case MEDIA_BUS_FMT_BGR888_1X24: 16708302c35SEric Anholt dpi_c |= VC4_SET_FIELD(DPI_FORMAT_24BIT_888_RGB, 16808302c35SEric Anholt DPI_FORMAT); 1693c270763SDave Stevenson dpi_c |= VC4_SET_FIELD(DPI_ORDER_BGR, 1703c270763SDave Stevenson DPI_ORDER); 17108302c35SEric Anholt break; 17208302c35SEric Anholt case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 17308302c35SEric Anholt dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_2, 17408302c35SEric Anholt DPI_FORMAT); 17508302c35SEric Anholt break; 17608302c35SEric Anholt case MEDIA_BUS_FMT_RGB666_1X18: 17708302c35SEric Anholt dpi_c |= VC4_SET_FIELD(DPI_FORMAT_18BIT_666_RGB_1, 17808302c35SEric Anholt DPI_FORMAT); 17908302c35SEric Anholt break; 18008302c35SEric Anholt case MEDIA_BUS_FMT_RGB565_1X16: 18108302c35SEric Anholt dpi_c |= VC4_SET_FIELD(DPI_FORMAT_16BIT_565_RGB_3, 18208302c35SEric Anholt DPI_FORMAT); 18308302c35SEric Anholt break; 18408302c35SEric Anholt default: 1853c270763SDave Stevenson DRM_ERROR("Unknown media bus format %d\n", 1863c270763SDave Stevenson bus_format); 18708302c35SEric Anholt break; 18808302c35SEric Anholt } 1893c270763SDave Stevenson } 1903c270763SDave Stevenson 1913c270763SDave Stevenson if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) 1923c270763SDave Stevenson dpi_c |= DPI_PIXEL_CLK_INVERT; 1933c270763SDave Stevenson 1943c270763SDave Stevenson if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW) 1953c270763SDave Stevenson dpi_c |= DPI_OUTPUT_ENABLE_INVERT; 19608302c35SEric Anholt } 19708302c35SEric Anholt 1987fea3c23SDave Stevenson if (mode->flags & DRM_MODE_FLAG_CSYNC) { 1997fea3c23SDave Stevenson if (mode->flags & DRM_MODE_FLAG_NCSYNC) 2007fea3c23SDave Stevenson dpi_c |= DPI_OUTPUT_ENABLE_INVERT; 2017fea3c23SDave Stevenson } else { 2027fea3c23SDave Stevenson dpi_c |= DPI_OUTPUT_ENABLE_MODE; 2037fea3c23SDave Stevenson 20408302c35SEric Anholt if (mode->flags & DRM_MODE_FLAG_NHSYNC) 20508302c35SEric Anholt dpi_c |= DPI_HSYNC_INVERT; 20608302c35SEric Anholt else if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) 20708302c35SEric Anholt dpi_c |= DPI_HSYNC_DISABLE; 20808302c35SEric Anholt 20908302c35SEric Anholt if (mode->flags & DRM_MODE_FLAG_NVSYNC) 21008302c35SEric Anholt dpi_c |= DPI_VSYNC_INVERT; 21108302c35SEric Anholt else if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) 21208302c35SEric Anholt dpi_c |= DPI_VSYNC_DISABLE; 2137fea3c23SDave Stevenson } 21408302c35SEric Anholt 21508302c35SEric Anholt DPI_WRITE(DPI_C, dpi_c); 21608302c35SEric Anholt 21708302c35SEric Anholt ret = clk_set_rate(dpi->pixel_clock, mode->clock * 1000); 21808302c35SEric Anholt if (ret) 21908302c35SEric Anholt DRM_ERROR("Failed to set clock rate: %d\n", ret); 22008302c35SEric Anholt 22108302c35SEric Anholt ret = clk_prepare_enable(dpi->pixel_clock); 22208302c35SEric Anholt if (ret) 22308302c35SEric Anholt DRM_ERROR("Failed to set clock rate: %d\n", ret); 22408302c35SEric Anholt } 22508302c35SEric Anholt 226c50a115bSJose Abreu static enum drm_mode_status vc4_dpi_encoder_mode_valid(struct drm_encoder *encoder, 227c50a115bSJose Abreu const struct drm_display_mode *mode) 228e2298350SMario Kleiner { 229c50a115bSJose Abreu if (mode->flags & DRM_MODE_FLAG_INTERLACE) 230c50a115bSJose Abreu return MODE_NO_INTERLACE; 231e2298350SMario Kleiner 232c50a115bSJose Abreu return MODE_OK; 233e2298350SMario Kleiner } 234e2298350SMario Kleiner 23508302c35SEric Anholt static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = { 23608302c35SEric Anholt .disable = vc4_dpi_encoder_disable, 23708302c35SEric Anholt .enable = vc4_dpi_encoder_enable, 238c50a115bSJose Abreu .mode_valid = vc4_dpi_encoder_mode_valid, 23908302c35SEric Anholt }; 24008302c35SEric Anholt 24108302c35SEric Anholt static const struct of_device_id vc4_dpi_dt_match[] = { 24208302c35SEric Anholt { .compatible = "brcm,bcm2835-dpi", .data = NULL }, 24308302c35SEric Anholt {} 24408302c35SEric Anholt }; 24508302c35SEric Anholt 2467b1298e0SEric Anholt /* Sets up the next link in the display chain, whether it's a panel or 2477b1298e0SEric Anholt * a bridge. 24808302c35SEric Anholt */ 2497b1298e0SEric Anholt static int vc4_dpi_init_bridge(struct vc4_dpi *dpi) 25008302c35SEric Anholt { 2517b1298e0SEric Anholt struct device *dev = &dpi->pdev->dev; 2528f6b06c1Sbenjamin.gaignard@linaro.org struct drm_bridge *bridge; 25308302c35SEric Anholt 2540caddbbfSMaxime Ripard bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); 2550caddbbfSMaxime Ripard if (IS_ERR(bridge)) { 2567b1298e0SEric Anholt /* If nothing was connected in the DT, that's not an 2577b1298e0SEric Anholt * error. 2587b1298e0SEric Anholt */ 2590caddbbfSMaxime Ripard if (PTR_ERR(bridge) == -ENODEV) 2607b1298e0SEric Anholt return 0; 2617b1298e0SEric Anholt else 2620caddbbfSMaxime Ripard return PTR_ERR(bridge); 2637b1298e0SEric Anholt } 26408302c35SEric Anholt 265a25b988fSLaurent Pinchart return drm_bridge_attach(dpi->encoder, bridge, NULL, 0); 26608302c35SEric Anholt } 26708302c35SEric Anholt 26808302c35SEric Anholt static int vc4_dpi_bind(struct device *dev, struct device *master, void *data) 26908302c35SEric Anholt { 27008302c35SEric Anholt struct platform_device *pdev = to_platform_device(dev); 27108302c35SEric Anholt struct drm_device *drm = dev_get_drvdata(master); 27208302c35SEric Anholt struct vc4_dev *vc4 = to_vc4_dev(drm); 27308302c35SEric Anholt struct vc4_dpi *dpi; 27408302c35SEric Anholt struct vc4_dpi_encoder *vc4_dpi_encoder; 27508302c35SEric Anholt int ret; 27608302c35SEric Anholt 27708302c35SEric Anholt dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL); 27808302c35SEric Anholt if (!dpi) 27908302c35SEric Anholt return -ENOMEM; 28008302c35SEric Anholt 28108302c35SEric Anholt vc4_dpi_encoder = devm_kzalloc(dev, sizeof(*vc4_dpi_encoder), 28208302c35SEric Anholt GFP_KERNEL); 28308302c35SEric Anholt if (!vc4_dpi_encoder) 28408302c35SEric Anholt return -ENOMEM; 28508302c35SEric Anholt vc4_dpi_encoder->base.type = VC4_ENCODER_TYPE_DPI; 28608302c35SEric Anholt vc4_dpi_encoder->dpi = dpi; 28708302c35SEric Anholt dpi->encoder = &vc4_dpi_encoder->base.base; 28808302c35SEric Anholt 28908302c35SEric Anholt dpi->pdev = pdev; 29008302c35SEric Anholt dpi->regs = vc4_ioremap_regs(pdev, 0); 29108302c35SEric Anholt if (IS_ERR(dpi->regs)) 29208302c35SEric Anholt return PTR_ERR(dpi->regs); 2933051719aSEric Anholt dpi->regset.base = dpi->regs; 2943051719aSEric Anholt dpi->regset.regs = dpi_regs; 2953051719aSEric Anholt dpi->regset.nregs = ARRAY_SIZE(dpi_regs); 29608302c35SEric Anholt 29708302c35SEric Anholt if (DPI_READ(DPI_ID) != DPI_ID_VALUE) { 29808302c35SEric Anholt dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n", 29908302c35SEric Anholt DPI_READ(DPI_ID), DPI_ID_VALUE); 30008302c35SEric Anholt return -ENODEV; 30108302c35SEric Anholt } 30208302c35SEric Anholt 30308302c35SEric Anholt dpi->core_clock = devm_clk_get(dev, "core"); 30408302c35SEric Anholt if (IS_ERR(dpi->core_clock)) { 30508302c35SEric Anholt ret = PTR_ERR(dpi->core_clock); 30608302c35SEric Anholt if (ret != -EPROBE_DEFER) 30708302c35SEric Anholt DRM_ERROR("Failed to get core clock: %d\n", ret); 30808302c35SEric Anholt return ret; 30908302c35SEric Anholt } 31008302c35SEric Anholt dpi->pixel_clock = devm_clk_get(dev, "pixel"); 31108302c35SEric Anholt if (IS_ERR(dpi->pixel_clock)) { 31208302c35SEric Anholt ret = PTR_ERR(dpi->pixel_clock); 31308302c35SEric Anholt if (ret != -EPROBE_DEFER) 31408302c35SEric Anholt DRM_ERROR("Failed to get pixel clock: %d\n", ret); 31508302c35SEric Anholt return ret; 31608302c35SEric Anholt } 31708302c35SEric Anholt 31808302c35SEric Anholt ret = clk_prepare_enable(dpi->core_clock); 31908302c35SEric Anholt if (ret) 32008302c35SEric Anholt DRM_ERROR("Failed to turn on core clock: %d\n", ret); 32108302c35SEric Anholt 322f6ebc1b0SThomas Zimmermann drm_simple_encoder_init(drm, dpi->encoder, DRM_MODE_ENCODER_DPI); 32308302c35SEric Anholt drm_encoder_helper_add(dpi->encoder, &vc4_dpi_encoder_helper_funcs); 32408302c35SEric Anholt 3257b1298e0SEric Anholt ret = vc4_dpi_init_bridge(dpi); 3267b1298e0SEric Anholt if (ret) 32708302c35SEric Anholt goto err_destroy_encoder; 32808302c35SEric Anholt 32908302c35SEric Anholt dev_set_drvdata(dev, dpi); 33008302c35SEric Anholt 33108302c35SEric Anholt vc4->dpi = dpi; 33208302c35SEric Anholt 333c9be804cSEric Anholt vc4_debugfs_add_regset32(drm, "dpi_regs", &dpi->regset); 334c9be804cSEric Anholt 33508302c35SEric Anholt return 0; 33608302c35SEric Anholt 33708302c35SEric Anholt err_destroy_encoder: 33808302c35SEric Anholt drm_encoder_cleanup(dpi->encoder); 33908302c35SEric Anholt clk_disable_unprepare(dpi->core_clock); 34008302c35SEric Anholt return ret; 34108302c35SEric Anholt } 34208302c35SEric Anholt 34308302c35SEric Anholt static void vc4_dpi_unbind(struct device *dev, struct device *master, 34408302c35SEric Anholt void *data) 34508302c35SEric Anholt { 34608302c35SEric Anholt struct drm_device *drm = dev_get_drvdata(master); 34708302c35SEric Anholt struct vc4_dev *vc4 = to_vc4_dev(drm); 34808302c35SEric Anholt struct vc4_dpi *dpi = dev_get_drvdata(dev); 34908302c35SEric Anholt 3508f6b06c1Sbenjamin.gaignard@linaro.org drm_of_panel_bridge_remove(dev->of_node, 0, 0); 35108302c35SEric Anholt 35208302c35SEric Anholt drm_encoder_cleanup(dpi->encoder); 35308302c35SEric Anholt 35408302c35SEric Anholt clk_disable_unprepare(dpi->core_clock); 35508302c35SEric Anholt 35608302c35SEric Anholt vc4->dpi = NULL; 35708302c35SEric Anholt } 35808302c35SEric Anholt 35908302c35SEric Anholt static const struct component_ops vc4_dpi_ops = { 36008302c35SEric Anholt .bind = vc4_dpi_bind, 36108302c35SEric Anholt .unbind = vc4_dpi_unbind, 36208302c35SEric Anholt }; 36308302c35SEric Anholt 36408302c35SEric Anholt static int vc4_dpi_dev_probe(struct platform_device *pdev) 36508302c35SEric Anholt { 36608302c35SEric Anholt return component_add(&pdev->dev, &vc4_dpi_ops); 36708302c35SEric Anholt } 36808302c35SEric Anholt 36908302c35SEric Anholt static int vc4_dpi_dev_remove(struct platform_device *pdev) 37008302c35SEric Anholt { 37108302c35SEric Anholt component_del(&pdev->dev, &vc4_dpi_ops); 37208302c35SEric Anholt return 0; 37308302c35SEric Anholt } 37408302c35SEric Anholt 37508302c35SEric Anholt struct platform_driver vc4_dpi_driver = { 37608302c35SEric Anholt .probe = vc4_dpi_dev_probe, 37708302c35SEric Anholt .remove = vc4_dpi_dev_remove, 37808302c35SEric Anholt .driver = { 37908302c35SEric Anholt .name = "vc4_dpi", 38008302c35SEric Anholt .of_match_table = vc4_dpi_dt_match, 38108302c35SEric Anholt }, 38208302c35SEric Anholt }; 383