16352cd45SJagan Teki // SPDX-License-Identifier: GPL-2.0+ 26352cd45SJagan Teki /* 36352cd45SJagan Teki * Copyright (C) 2021 RenewOutReach 46352cd45SJagan Teki * Copyright (C) 2021 Amarula Solutions(India) 56352cd45SJagan Teki * 66352cd45SJagan Teki * Author: 76352cd45SJagan Teki * Jagan Teki <jagan@amarulasolutions.com> 86352cd45SJagan Teki * Christopher Vollo <chris@renewoutreach.org> 96352cd45SJagan Teki */ 106352cd45SJagan Teki 116352cd45SJagan Teki #include <drm/drm_atomic_helper.h> 126352cd45SJagan Teki #include <drm/drm_of.h> 136352cd45SJagan Teki #include <drm/drm_print.h> 146352cd45SJagan Teki #include <drm/drm_mipi_dsi.h> 156352cd45SJagan Teki 166352cd45SJagan Teki #include <linux/delay.h> 176352cd45SJagan Teki #include <linux/gpio/consumer.h> 186352cd45SJagan Teki #include <linux/i2c.h> 1972bd9ea3SVille Syrjälä #include <linux/media-bus-format.h> 206352cd45SJagan Teki #include <linux/module.h> 216352cd45SJagan Teki #include <linux/regmap.h> 226352cd45SJagan Teki #include <linux/regulator/consumer.h> 236352cd45SJagan Teki 246352cd45SJagan Teki enum cmd_registers { 256352cd45SJagan Teki WR_INPUT_SOURCE = 0x05, /* Write Input Source Select */ 266352cd45SJagan Teki WR_EXT_SOURCE_FMT = 0x07, /* Write External Video Source Format */ 276352cd45SJagan Teki WR_IMAGE_CROP = 0x10, /* Write Image Crop */ 286352cd45SJagan Teki WR_DISPLAY_SIZE = 0x12, /* Write Display Size */ 296352cd45SJagan Teki WR_IMAGE_FREEZE = 0x1A, /* Write Image Freeze */ 306352cd45SJagan Teki WR_INPUT_IMAGE_SIZE = 0x2E, /* Write External Input Image Size */ 316352cd45SJagan Teki WR_RGB_LED_EN = 0x52, /* Write RGB LED Enable */ 326352cd45SJagan Teki WR_RGB_LED_CURRENT = 0x54, /* Write RGB LED Current */ 336352cd45SJagan Teki WR_RGB_LED_MAX_CURRENT = 0x5C, /* Write RGB LED Max Current */ 346352cd45SJagan Teki WR_DSI_HS_CLK = 0xBD, /* Write DSI HS Clock */ 356352cd45SJagan Teki RD_DEVICE_ID = 0xD4, /* Read Controller Device ID */ 366352cd45SJagan Teki WR_DSI_PORT_EN = 0xD7, /* Write DSI Port Enable */ 376352cd45SJagan Teki }; 386352cd45SJagan Teki 396352cd45SJagan Teki enum input_source { 406352cd45SJagan Teki INPUT_EXTERNAL_VIDEO = 0, 416352cd45SJagan Teki INPUT_TEST_PATTERN, 426352cd45SJagan Teki INPUT_SPLASH_SCREEN, 436352cd45SJagan Teki }; 446352cd45SJagan Teki 456352cd45SJagan Teki #define DEV_ID_MASK GENMASK(3, 0) 466352cd45SJagan Teki #define IMAGE_FREESE_EN BIT(0) 476352cd45SJagan Teki #define DSI_PORT_EN 0 486352cd45SJagan Teki #define EXT_SOURCE_FMT_DSI 0 496352cd45SJagan Teki #define RED_LED_EN BIT(0) 506352cd45SJagan Teki #define GREEN_LED_EN BIT(1) 516352cd45SJagan Teki #define BLUE_LED_EN BIT(2) 526352cd45SJagan Teki #define LED_MASK GENMASK(2, 0) 536352cd45SJagan Teki #define MAX_BYTE_SIZE 8 546352cd45SJagan Teki 556352cd45SJagan Teki struct dlpc { 566352cd45SJagan Teki struct device *dev; 576352cd45SJagan Teki struct drm_bridge bridge; 586352cd45SJagan Teki struct drm_bridge *next_bridge; 596352cd45SJagan Teki struct device_node *host_node; 606352cd45SJagan Teki struct mipi_dsi_device *dsi; 616352cd45SJagan Teki struct drm_display_mode mode; 626352cd45SJagan Teki 636352cd45SJagan Teki struct gpio_desc *enable_gpio; 646352cd45SJagan Teki struct regulator *vcc_intf; 656352cd45SJagan Teki struct regulator *vcc_flsh; 666352cd45SJagan Teki struct regmap *regmap; 676352cd45SJagan Teki unsigned int dsi_lanes; 686352cd45SJagan Teki }; 696352cd45SJagan Teki 706352cd45SJagan Teki static inline struct dlpc *bridge_to_dlpc(struct drm_bridge *bridge) 716352cd45SJagan Teki { 726352cd45SJagan Teki return container_of(bridge, struct dlpc, bridge); 736352cd45SJagan Teki } 746352cd45SJagan Teki 756352cd45SJagan Teki static bool dlpc_writeable_noinc_reg(struct device *dev, unsigned int reg) 766352cd45SJagan Teki { 776352cd45SJagan Teki switch (reg) { 786352cd45SJagan Teki case WR_IMAGE_CROP: 796352cd45SJagan Teki case WR_DISPLAY_SIZE: 806352cd45SJagan Teki case WR_INPUT_IMAGE_SIZE: 816352cd45SJagan Teki case WR_DSI_HS_CLK: 826352cd45SJagan Teki return true; 836352cd45SJagan Teki default: 846352cd45SJagan Teki return false; 856352cd45SJagan Teki } 866352cd45SJagan Teki } 876352cd45SJagan Teki 886352cd45SJagan Teki static const struct regmap_range dlpc_volatile_ranges[] = { 896352cd45SJagan Teki { .range_min = 0x10, .range_max = 0xBF }, 906352cd45SJagan Teki }; 916352cd45SJagan Teki 926352cd45SJagan Teki static const struct regmap_access_table dlpc_volatile_table = { 936352cd45SJagan Teki .yes_ranges = dlpc_volatile_ranges, 946352cd45SJagan Teki .n_yes_ranges = ARRAY_SIZE(dlpc_volatile_ranges), 956352cd45SJagan Teki }; 966352cd45SJagan Teki 976352cd45SJagan Teki static struct regmap_config dlpc_regmap_config = { 986352cd45SJagan Teki .reg_bits = 8, 996352cd45SJagan Teki .val_bits = 8, 1006352cd45SJagan Teki .max_register = WR_DSI_PORT_EN, 1016352cd45SJagan Teki .writeable_noinc_reg = dlpc_writeable_noinc_reg, 1026352cd45SJagan Teki .volatile_table = &dlpc_volatile_table, 1036352cd45SJagan Teki .cache_type = REGCACHE_RBTREE, 1046352cd45SJagan Teki .name = "dlpc3433", 1056352cd45SJagan Teki }; 1066352cd45SJagan Teki 1076352cd45SJagan Teki static void dlpc_atomic_enable(struct drm_bridge *bridge, 1086352cd45SJagan Teki struct drm_bridge_state *old_bridge_state) 1096352cd45SJagan Teki { 1106352cd45SJagan Teki struct dlpc *dlpc = bridge_to_dlpc(bridge); 1116352cd45SJagan Teki struct device *dev = dlpc->dev; 1126352cd45SJagan Teki struct drm_display_mode *mode = &dlpc->mode; 1136352cd45SJagan Teki struct regmap *regmap = dlpc->regmap; 1146352cd45SJagan Teki char buf[MAX_BYTE_SIZE]; 1156352cd45SJagan Teki unsigned int devid; 1166352cd45SJagan Teki 1176352cd45SJagan Teki regmap_read(regmap, RD_DEVICE_ID, &devid); 1186352cd45SJagan Teki devid &= DEV_ID_MASK; 1196352cd45SJagan Teki 1206352cd45SJagan Teki DRM_DEV_DEBUG(dev, "DLPC3433 device id: 0x%02x\n", devid); 1216352cd45SJagan Teki 1226352cd45SJagan Teki if (devid != 0x01) { 1236352cd45SJagan Teki DRM_DEV_ERROR(dev, "Unsupported DLPC device id: 0x%02x\n", devid); 1246352cd45SJagan Teki return; 1256352cd45SJagan Teki } 1266352cd45SJagan Teki 1276352cd45SJagan Teki /* disable image freeze */ 1286352cd45SJagan Teki regmap_write(regmap, WR_IMAGE_FREEZE, IMAGE_FREESE_EN); 1296352cd45SJagan Teki 1306352cd45SJagan Teki /* enable DSI port */ 1316352cd45SJagan Teki regmap_write(regmap, WR_DSI_PORT_EN, DSI_PORT_EN); 1326352cd45SJagan Teki 1336352cd45SJagan Teki memset(buf, 0, MAX_BYTE_SIZE); 1346352cd45SJagan Teki 1356352cd45SJagan Teki /* set image crop */ 1366352cd45SJagan Teki buf[4] = mode->hdisplay & 0xff; 1376352cd45SJagan Teki buf[5] = (mode->hdisplay & 0xff00) >> 8; 1386352cd45SJagan Teki buf[6] = mode->vdisplay & 0xff; 1396352cd45SJagan Teki buf[7] = (mode->vdisplay & 0xff00) >> 8; 1406352cd45SJagan Teki regmap_noinc_write(regmap, WR_IMAGE_CROP, buf, MAX_BYTE_SIZE); 1416352cd45SJagan Teki 1426352cd45SJagan Teki /* set display size */ 1436352cd45SJagan Teki buf[4] = mode->hdisplay & 0xff; 1446352cd45SJagan Teki buf[5] = (mode->hdisplay & 0xff00) >> 8; 1456352cd45SJagan Teki buf[6] = mode->vdisplay & 0xff; 1466352cd45SJagan Teki buf[7] = (mode->vdisplay & 0xff00) >> 8; 1476352cd45SJagan Teki regmap_noinc_write(regmap, WR_DISPLAY_SIZE, buf, MAX_BYTE_SIZE); 1486352cd45SJagan Teki 1496352cd45SJagan Teki /* set input image size */ 1506352cd45SJagan Teki buf[0] = mode->hdisplay & 0xff; 1516352cd45SJagan Teki buf[1] = (mode->hdisplay & 0xff00) >> 8; 1526352cd45SJagan Teki buf[2] = mode->vdisplay & 0xff; 1536352cd45SJagan Teki buf[3] = (mode->vdisplay & 0xff00) >> 8; 1546352cd45SJagan Teki regmap_noinc_write(regmap, WR_INPUT_IMAGE_SIZE, buf, 4); 1556352cd45SJagan Teki 1566352cd45SJagan Teki /* set external video port */ 1576352cd45SJagan Teki regmap_write(regmap, WR_INPUT_SOURCE, INPUT_EXTERNAL_VIDEO); 1586352cd45SJagan Teki 1596352cd45SJagan Teki /* set external video format select as DSI */ 1606352cd45SJagan Teki regmap_write(regmap, WR_EXT_SOURCE_FMT, EXT_SOURCE_FMT_DSI); 1616352cd45SJagan Teki 1626352cd45SJagan Teki /* disable image freeze */ 1636352cd45SJagan Teki regmap_write(regmap, WR_IMAGE_FREEZE, 0x00); 1646352cd45SJagan Teki 1656352cd45SJagan Teki /* enable RGB led */ 1666352cd45SJagan Teki regmap_update_bits(regmap, WR_RGB_LED_EN, LED_MASK, 1676352cd45SJagan Teki RED_LED_EN | GREEN_LED_EN | BLUE_LED_EN); 1686352cd45SJagan Teki 1696352cd45SJagan Teki msleep(10); 1706352cd45SJagan Teki } 1716352cd45SJagan Teki 1726352cd45SJagan Teki static void dlpc_atomic_pre_enable(struct drm_bridge *bridge, 1736352cd45SJagan Teki struct drm_bridge_state *old_bridge_state) 1746352cd45SJagan Teki { 1756352cd45SJagan Teki struct dlpc *dlpc = bridge_to_dlpc(bridge); 1766352cd45SJagan Teki int ret; 1776352cd45SJagan Teki 1786352cd45SJagan Teki gpiod_set_value(dlpc->enable_gpio, 1); 1796352cd45SJagan Teki 1806352cd45SJagan Teki msleep(500); 1816352cd45SJagan Teki 1826352cd45SJagan Teki ret = regulator_enable(dlpc->vcc_intf); 1836352cd45SJagan Teki if (ret) 1846352cd45SJagan Teki DRM_DEV_ERROR(dlpc->dev, 1856352cd45SJagan Teki "failed to enable VCC_INTF regulator: %d\n", ret); 1866352cd45SJagan Teki 1876352cd45SJagan Teki ret = regulator_enable(dlpc->vcc_flsh); 1886352cd45SJagan Teki if (ret) 1896352cd45SJagan Teki DRM_DEV_ERROR(dlpc->dev, 1906352cd45SJagan Teki "failed to enable VCC_FLSH regulator: %d\n", ret); 1916352cd45SJagan Teki 1926352cd45SJagan Teki msleep(10); 1936352cd45SJagan Teki } 1946352cd45SJagan Teki 1956352cd45SJagan Teki static void dlpc_atomic_post_disable(struct drm_bridge *bridge, 1966352cd45SJagan Teki struct drm_bridge_state *old_bridge_state) 1976352cd45SJagan Teki { 1986352cd45SJagan Teki struct dlpc *dlpc = bridge_to_dlpc(bridge); 1996352cd45SJagan Teki 2006352cd45SJagan Teki regulator_disable(dlpc->vcc_flsh); 2016352cd45SJagan Teki regulator_disable(dlpc->vcc_intf); 2026352cd45SJagan Teki 2036352cd45SJagan Teki msleep(10); 2046352cd45SJagan Teki 2056352cd45SJagan Teki gpiod_set_value(dlpc->enable_gpio, 0); 2066352cd45SJagan Teki 2076352cd45SJagan Teki msleep(500); 2086352cd45SJagan Teki } 2096352cd45SJagan Teki 2106352cd45SJagan Teki #define MAX_INPUT_SEL_FORMATS 1 2116352cd45SJagan Teki 2126352cd45SJagan Teki static u32 * 2136352cd45SJagan Teki dlpc_atomic_get_input_bus_fmts(struct drm_bridge *bridge, 2146352cd45SJagan Teki struct drm_bridge_state *bridge_state, 2156352cd45SJagan Teki struct drm_crtc_state *crtc_state, 2166352cd45SJagan Teki struct drm_connector_state *conn_state, 2176352cd45SJagan Teki u32 output_fmt, 2186352cd45SJagan Teki unsigned int *num_input_fmts) 2196352cd45SJagan Teki { 2206352cd45SJagan Teki u32 *input_fmts; 2216352cd45SJagan Teki 2226352cd45SJagan Teki *num_input_fmts = 0; 2236352cd45SJagan Teki 2246352cd45SJagan Teki input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts), 2256352cd45SJagan Teki GFP_KERNEL); 2266352cd45SJagan Teki if (!input_fmts) 2276352cd45SJagan Teki return NULL; 2286352cd45SJagan Teki 2296352cd45SJagan Teki /* This is the DSI-end bus format */ 2306352cd45SJagan Teki input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; 2316352cd45SJagan Teki *num_input_fmts = 1; 2326352cd45SJagan Teki 2336352cd45SJagan Teki return input_fmts; 2346352cd45SJagan Teki } 2356352cd45SJagan Teki 2366352cd45SJagan Teki static void dlpc_mode_set(struct drm_bridge *bridge, 2376352cd45SJagan Teki const struct drm_display_mode *mode, 2386352cd45SJagan Teki const struct drm_display_mode *adjusted_mode) 2396352cd45SJagan Teki { 2406352cd45SJagan Teki struct dlpc *dlpc = bridge_to_dlpc(bridge); 2416352cd45SJagan Teki 2426352cd45SJagan Teki drm_mode_copy(&dlpc->mode, adjusted_mode); 2436352cd45SJagan Teki } 2446352cd45SJagan Teki 2456352cd45SJagan Teki static int dlpc_attach(struct drm_bridge *bridge, 2466352cd45SJagan Teki enum drm_bridge_attach_flags flags) 2476352cd45SJagan Teki { 2486352cd45SJagan Teki struct dlpc *dlpc = bridge_to_dlpc(bridge); 2496352cd45SJagan Teki 2506352cd45SJagan Teki return drm_bridge_attach(bridge->encoder, dlpc->next_bridge, bridge, flags); 2516352cd45SJagan Teki } 2526352cd45SJagan Teki 2536352cd45SJagan Teki static const struct drm_bridge_funcs dlpc_bridge_funcs = { 2546352cd45SJagan Teki .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 2556352cd45SJagan Teki .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 2566352cd45SJagan Teki .atomic_get_input_bus_fmts = dlpc_atomic_get_input_bus_fmts, 2576352cd45SJagan Teki .atomic_reset = drm_atomic_helper_bridge_reset, 2586352cd45SJagan Teki .atomic_pre_enable = dlpc_atomic_pre_enable, 2596352cd45SJagan Teki .atomic_enable = dlpc_atomic_enable, 2606352cd45SJagan Teki .atomic_post_disable = dlpc_atomic_post_disable, 2616352cd45SJagan Teki .mode_set = dlpc_mode_set, 2626352cd45SJagan Teki .attach = dlpc_attach, 2636352cd45SJagan Teki }; 2646352cd45SJagan Teki 2656352cd45SJagan Teki static int dlpc3433_parse_dt(struct dlpc *dlpc) 2666352cd45SJagan Teki { 2676352cd45SJagan Teki struct device *dev = dlpc->dev; 2686352cd45SJagan Teki struct device_node *endpoint; 2696352cd45SJagan Teki int ret; 2706352cd45SJagan Teki 2716352cd45SJagan Teki dlpc->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 2726352cd45SJagan Teki if (IS_ERR(dlpc->enable_gpio)) 2736352cd45SJagan Teki return PTR_ERR(dlpc->enable_gpio); 2746352cd45SJagan Teki 2756352cd45SJagan Teki dlpc->vcc_intf = devm_regulator_get(dlpc->dev, "vcc_intf"); 2766352cd45SJagan Teki if (IS_ERR(dlpc->vcc_intf)) 2776352cd45SJagan Teki return dev_err_probe(dev, PTR_ERR(dlpc->vcc_intf), 2786352cd45SJagan Teki "failed to get VCC_INTF supply\n"); 2796352cd45SJagan Teki 2806352cd45SJagan Teki dlpc->vcc_flsh = devm_regulator_get(dlpc->dev, "vcc_flsh"); 2816352cd45SJagan Teki if (IS_ERR(dlpc->vcc_flsh)) 2826352cd45SJagan Teki return dev_err_probe(dev, PTR_ERR(dlpc->vcc_flsh), 2836352cd45SJagan Teki "failed to get VCC_FLSH supply\n"); 2846352cd45SJagan Teki 2856352cd45SJagan Teki dlpc->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); 2866352cd45SJagan Teki if (IS_ERR(dlpc->next_bridge)) 2876352cd45SJagan Teki return PTR_ERR(dlpc->next_bridge); 2886352cd45SJagan Teki 2896352cd45SJagan Teki endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0); 2906352cd45SJagan Teki dlpc->dsi_lanes = of_property_count_u32_elems(endpoint, "data-lanes"); 2916352cd45SJagan Teki if (dlpc->dsi_lanes < 0 || dlpc->dsi_lanes > 4) { 2926352cd45SJagan Teki ret = -EINVAL; 2936352cd45SJagan Teki goto err_put_endpoint; 2946352cd45SJagan Teki } 2956352cd45SJagan Teki 2966352cd45SJagan Teki dlpc->host_node = of_graph_get_remote_port_parent(endpoint); 2976352cd45SJagan Teki if (!dlpc->host_node) { 2986352cd45SJagan Teki ret = -ENODEV; 2996352cd45SJagan Teki goto err_put_host; 3006352cd45SJagan Teki } 3016352cd45SJagan Teki 3026352cd45SJagan Teki of_node_put(endpoint); 3036352cd45SJagan Teki 3046352cd45SJagan Teki return 0; 3056352cd45SJagan Teki 3066352cd45SJagan Teki err_put_host: 3076352cd45SJagan Teki of_node_put(dlpc->host_node); 3086352cd45SJagan Teki err_put_endpoint: 3096352cd45SJagan Teki of_node_put(endpoint); 3106352cd45SJagan Teki return ret; 3116352cd45SJagan Teki } 3126352cd45SJagan Teki 3136352cd45SJagan Teki static int dlpc_host_attach(struct dlpc *dlpc) 3146352cd45SJagan Teki { 3156352cd45SJagan Teki struct device *dev = dlpc->dev; 3166352cd45SJagan Teki struct mipi_dsi_host *host; 3176352cd45SJagan Teki struct mipi_dsi_device_info info = { 3186352cd45SJagan Teki .type = "dlpc3433", 3196352cd45SJagan Teki .channel = 0, 3206352cd45SJagan Teki .node = NULL, 3216352cd45SJagan Teki }; 322*7962ae5aSNícolas F. R. A. Prado int ret; 3236352cd45SJagan Teki 3246352cd45SJagan Teki host = of_find_mipi_dsi_host_by_node(dlpc->host_node); 325*7962ae5aSNícolas F. R. A. Prado if (!host) 326*7962ae5aSNícolas F. R. A. Prado return dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n"); 3276352cd45SJagan Teki 3286352cd45SJagan Teki dlpc->dsi = mipi_dsi_device_register_full(host, &info); 3296352cd45SJagan Teki if (IS_ERR(dlpc->dsi)) { 3306352cd45SJagan Teki DRM_DEV_ERROR(dev, "failed to create dsi device\n"); 3316352cd45SJagan Teki return PTR_ERR(dlpc->dsi); 3326352cd45SJagan Teki } 3336352cd45SJagan Teki 3346352cd45SJagan Teki dlpc->dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST; 3356352cd45SJagan Teki dlpc->dsi->format = MIPI_DSI_FMT_RGB565; 3366352cd45SJagan Teki dlpc->dsi->lanes = dlpc->dsi_lanes; 3376352cd45SJagan Teki 338*7962ae5aSNícolas F. R. A. Prado ret = devm_mipi_dsi_attach(dev, dlpc->dsi); 339*7962ae5aSNícolas F. R. A. Prado if (ret) 340*7962ae5aSNícolas F. R. A. Prado DRM_DEV_ERROR(dev, "failed to attach dsi host\n"); 341*7962ae5aSNícolas F. R. A. Prado 342*7962ae5aSNícolas F. R. A. Prado return ret; 3436352cd45SJagan Teki } 3446352cd45SJagan Teki 3456352cd45SJagan Teki static int dlpc3433_probe(struct i2c_client *client) 3466352cd45SJagan Teki { 3476352cd45SJagan Teki struct device *dev = &client->dev; 3486352cd45SJagan Teki struct dlpc *dlpc; 3496352cd45SJagan Teki int ret; 3506352cd45SJagan Teki 3516352cd45SJagan Teki dlpc = devm_kzalloc(dev, sizeof(*dlpc), GFP_KERNEL); 3526352cd45SJagan Teki if (!dlpc) 3536352cd45SJagan Teki return -ENOMEM; 3546352cd45SJagan Teki 3556352cd45SJagan Teki dlpc->dev = dev; 3566352cd45SJagan Teki 3576352cd45SJagan Teki dlpc->regmap = devm_regmap_init_i2c(client, &dlpc_regmap_config); 3586352cd45SJagan Teki if (IS_ERR(dlpc->regmap)) 3596352cd45SJagan Teki return PTR_ERR(dlpc->regmap); 3606352cd45SJagan Teki 3616352cd45SJagan Teki ret = dlpc3433_parse_dt(dlpc); 3626352cd45SJagan Teki if (ret) 3636352cd45SJagan Teki return ret; 3646352cd45SJagan Teki 3656352cd45SJagan Teki dev_set_drvdata(dev, dlpc); 3666352cd45SJagan Teki i2c_set_clientdata(client, dlpc); 3676352cd45SJagan Teki 3686352cd45SJagan Teki dlpc->bridge.funcs = &dlpc_bridge_funcs; 3696352cd45SJagan Teki dlpc->bridge.of_node = dev->of_node; 3706352cd45SJagan Teki drm_bridge_add(&dlpc->bridge); 3716352cd45SJagan Teki 3726352cd45SJagan Teki ret = dlpc_host_attach(dlpc); 373*7962ae5aSNícolas F. R. A. Prado if (ret) 3746352cd45SJagan Teki goto err_remove_bridge; 3756352cd45SJagan Teki 3766352cd45SJagan Teki return 0; 3776352cd45SJagan Teki 3786352cd45SJagan Teki err_remove_bridge: 3796352cd45SJagan Teki drm_bridge_remove(&dlpc->bridge); 3806352cd45SJagan Teki return ret; 3816352cd45SJagan Teki } 3826352cd45SJagan Teki 383ed5c2f5fSUwe Kleine-König static void dlpc3433_remove(struct i2c_client *client) 3846352cd45SJagan Teki { 3856352cd45SJagan Teki struct dlpc *dlpc = i2c_get_clientdata(client); 3866352cd45SJagan Teki 3876352cd45SJagan Teki drm_bridge_remove(&dlpc->bridge); 3886352cd45SJagan Teki of_node_put(dlpc->host_node); 3896352cd45SJagan Teki } 3906352cd45SJagan Teki 3916352cd45SJagan Teki static const struct i2c_device_id dlpc3433_id[] = { 3926352cd45SJagan Teki { "ti,dlpc3433", 0 }, 3936352cd45SJagan Teki { /* sentinel */ } 3946352cd45SJagan Teki }; 3956352cd45SJagan Teki MODULE_DEVICE_TABLE(i2c, dlpc3433_id); 3966352cd45SJagan Teki 3976352cd45SJagan Teki static const struct of_device_id dlpc3433_match_table[] = { 3986352cd45SJagan Teki { .compatible = "ti,dlpc3433" }, 3996352cd45SJagan Teki { /* sentinel */ } 4006352cd45SJagan Teki }; 4016352cd45SJagan Teki MODULE_DEVICE_TABLE(of, dlpc3433_match_table); 4026352cd45SJagan Teki 4036352cd45SJagan Teki static struct i2c_driver dlpc3433_driver = { 404332af828SUwe Kleine-König .probe = dlpc3433_probe, 4056352cd45SJagan Teki .remove = dlpc3433_remove, 4066352cd45SJagan Teki .id_table = dlpc3433_id, 4076352cd45SJagan Teki .driver = { 4086352cd45SJagan Teki .name = "ti-dlpc3433", 4096352cd45SJagan Teki .of_match_table = dlpc3433_match_table, 4106352cd45SJagan Teki }, 4116352cd45SJagan Teki }; 4126352cd45SJagan Teki module_i2c_driver(dlpc3433_driver); 4136352cd45SJagan Teki 4146352cd45SJagan Teki MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>"); 4156352cd45SJagan Teki MODULE_AUTHOR("Christopher Vollo <chris@renewoutreach.org>"); 4166352cd45SJagan Teki MODULE_DESCRIPTION("TI DLPC3433 MIPI DSI Display Controller Bridge"); 4176352cd45SJagan Teki MODULE_LICENSE("GPL"); 418