1*6352cd45SJagan Teki // SPDX-License-Identifier: GPL-2.0+ 2*6352cd45SJagan Teki /* 3*6352cd45SJagan Teki * Copyright (C) 2021 RenewOutReach 4*6352cd45SJagan Teki * Copyright (C) 2021 Amarula Solutions(India) 5*6352cd45SJagan Teki * 6*6352cd45SJagan Teki * Author: 7*6352cd45SJagan Teki * Jagan Teki <jagan@amarulasolutions.com> 8*6352cd45SJagan Teki * Christopher Vollo <chris@renewoutreach.org> 9*6352cd45SJagan Teki */ 10*6352cd45SJagan Teki 11*6352cd45SJagan Teki #include <drm/drm_atomic_helper.h> 12*6352cd45SJagan Teki #include <drm/drm_of.h> 13*6352cd45SJagan Teki #include <drm/drm_print.h> 14*6352cd45SJagan Teki #include <drm/drm_mipi_dsi.h> 15*6352cd45SJagan Teki 16*6352cd45SJagan Teki #include <linux/delay.h> 17*6352cd45SJagan Teki #include <linux/gpio/consumer.h> 18*6352cd45SJagan Teki #include <linux/i2c.h> 19*6352cd45SJagan Teki #include <linux/module.h> 20*6352cd45SJagan Teki #include <linux/regmap.h> 21*6352cd45SJagan Teki #include <linux/regulator/consumer.h> 22*6352cd45SJagan Teki 23*6352cd45SJagan Teki enum cmd_registers { 24*6352cd45SJagan Teki WR_INPUT_SOURCE = 0x05, /* Write Input Source Select */ 25*6352cd45SJagan Teki WR_EXT_SOURCE_FMT = 0x07, /* Write External Video Source Format */ 26*6352cd45SJagan Teki WR_IMAGE_CROP = 0x10, /* Write Image Crop */ 27*6352cd45SJagan Teki WR_DISPLAY_SIZE = 0x12, /* Write Display Size */ 28*6352cd45SJagan Teki WR_IMAGE_FREEZE = 0x1A, /* Write Image Freeze */ 29*6352cd45SJagan Teki WR_INPUT_IMAGE_SIZE = 0x2E, /* Write External Input Image Size */ 30*6352cd45SJagan Teki WR_RGB_LED_EN = 0x52, /* Write RGB LED Enable */ 31*6352cd45SJagan Teki WR_RGB_LED_CURRENT = 0x54, /* Write RGB LED Current */ 32*6352cd45SJagan Teki WR_RGB_LED_MAX_CURRENT = 0x5C, /* Write RGB LED Max Current */ 33*6352cd45SJagan Teki WR_DSI_HS_CLK = 0xBD, /* Write DSI HS Clock */ 34*6352cd45SJagan Teki RD_DEVICE_ID = 0xD4, /* Read Controller Device ID */ 35*6352cd45SJagan Teki WR_DSI_PORT_EN = 0xD7, /* Write DSI Port Enable */ 36*6352cd45SJagan Teki }; 37*6352cd45SJagan Teki 38*6352cd45SJagan Teki enum input_source { 39*6352cd45SJagan Teki INPUT_EXTERNAL_VIDEO = 0, 40*6352cd45SJagan Teki INPUT_TEST_PATTERN, 41*6352cd45SJagan Teki INPUT_SPLASH_SCREEN, 42*6352cd45SJagan Teki }; 43*6352cd45SJagan Teki 44*6352cd45SJagan Teki #define DEV_ID_MASK GENMASK(3, 0) 45*6352cd45SJagan Teki #define IMAGE_FREESE_EN BIT(0) 46*6352cd45SJagan Teki #define DSI_PORT_EN 0 47*6352cd45SJagan Teki #define EXT_SOURCE_FMT_DSI 0 48*6352cd45SJagan Teki #define RED_LED_EN BIT(0) 49*6352cd45SJagan Teki #define GREEN_LED_EN BIT(1) 50*6352cd45SJagan Teki #define BLUE_LED_EN BIT(2) 51*6352cd45SJagan Teki #define LED_MASK GENMASK(2, 0) 52*6352cd45SJagan Teki #define MAX_BYTE_SIZE 8 53*6352cd45SJagan Teki 54*6352cd45SJagan Teki struct dlpc { 55*6352cd45SJagan Teki struct device *dev; 56*6352cd45SJagan Teki struct drm_bridge bridge; 57*6352cd45SJagan Teki struct drm_bridge *next_bridge; 58*6352cd45SJagan Teki struct device_node *host_node; 59*6352cd45SJagan Teki struct mipi_dsi_device *dsi; 60*6352cd45SJagan Teki struct drm_display_mode mode; 61*6352cd45SJagan Teki 62*6352cd45SJagan Teki struct gpio_desc *enable_gpio; 63*6352cd45SJagan Teki struct regulator *vcc_intf; 64*6352cd45SJagan Teki struct regulator *vcc_flsh; 65*6352cd45SJagan Teki struct regmap *regmap; 66*6352cd45SJagan Teki unsigned int dsi_lanes; 67*6352cd45SJagan Teki }; 68*6352cd45SJagan Teki 69*6352cd45SJagan Teki static inline struct dlpc *bridge_to_dlpc(struct drm_bridge *bridge) 70*6352cd45SJagan Teki { 71*6352cd45SJagan Teki return container_of(bridge, struct dlpc, bridge); 72*6352cd45SJagan Teki } 73*6352cd45SJagan Teki 74*6352cd45SJagan Teki static bool dlpc_writeable_noinc_reg(struct device *dev, unsigned int reg) 75*6352cd45SJagan Teki { 76*6352cd45SJagan Teki switch (reg) { 77*6352cd45SJagan Teki case WR_IMAGE_CROP: 78*6352cd45SJagan Teki case WR_DISPLAY_SIZE: 79*6352cd45SJagan Teki case WR_INPUT_IMAGE_SIZE: 80*6352cd45SJagan Teki case WR_DSI_HS_CLK: 81*6352cd45SJagan Teki return true; 82*6352cd45SJagan Teki default: 83*6352cd45SJagan Teki return false; 84*6352cd45SJagan Teki } 85*6352cd45SJagan Teki } 86*6352cd45SJagan Teki 87*6352cd45SJagan Teki static const struct regmap_range dlpc_volatile_ranges[] = { 88*6352cd45SJagan Teki { .range_min = 0x10, .range_max = 0xBF }, 89*6352cd45SJagan Teki }; 90*6352cd45SJagan Teki 91*6352cd45SJagan Teki static const struct regmap_access_table dlpc_volatile_table = { 92*6352cd45SJagan Teki .yes_ranges = dlpc_volatile_ranges, 93*6352cd45SJagan Teki .n_yes_ranges = ARRAY_SIZE(dlpc_volatile_ranges), 94*6352cd45SJagan Teki }; 95*6352cd45SJagan Teki 96*6352cd45SJagan Teki static struct regmap_config dlpc_regmap_config = { 97*6352cd45SJagan Teki .reg_bits = 8, 98*6352cd45SJagan Teki .val_bits = 8, 99*6352cd45SJagan Teki .max_register = WR_DSI_PORT_EN, 100*6352cd45SJagan Teki .writeable_noinc_reg = dlpc_writeable_noinc_reg, 101*6352cd45SJagan Teki .volatile_table = &dlpc_volatile_table, 102*6352cd45SJagan Teki .cache_type = REGCACHE_RBTREE, 103*6352cd45SJagan Teki .name = "dlpc3433", 104*6352cd45SJagan Teki }; 105*6352cd45SJagan Teki 106*6352cd45SJagan Teki static void dlpc_atomic_enable(struct drm_bridge *bridge, 107*6352cd45SJagan Teki struct drm_bridge_state *old_bridge_state) 108*6352cd45SJagan Teki { 109*6352cd45SJagan Teki struct dlpc *dlpc = bridge_to_dlpc(bridge); 110*6352cd45SJagan Teki struct device *dev = dlpc->dev; 111*6352cd45SJagan Teki struct drm_display_mode *mode = &dlpc->mode; 112*6352cd45SJagan Teki struct regmap *regmap = dlpc->regmap; 113*6352cd45SJagan Teki char buf[MAX_BYTE_SIZE]; 114*6352cd45SJagan Teki unsigned int devid; 115*6352cd45SJagan Teki 116*6352cd45SJagan Teki regmap_read(regmap, RD_DEVICE_ID, &devid); 117*6352cd45SJagan Teki devid &= DEV_ID_MASK; 118*6352cd45SJagan Teki 119*6352cd45SJagan Teki DRM_DEV_DEBUG(dev, "DLPC3433 device id: 0x%02x\n", devid); 120*6352cd45SJagan Teki 121*6352cd45SJagan Teki if (devid != 0x01) { 122*6352cd45SJagan Teki DRM_DEV_ERROR(dev, "Unsupported DLPC device id: 0x%02x\n", devid); 123*6352cd45SJagan Teki return; 124*6352cd45SJagan Teki } 125*6352cd45SJagan Teki 126*6352cd45SJagan Teki /* disable image freeze */ 127*6352cd45SJagan Teki regmap_write(regmap, WR_IMAGE_FREEZE, IMAGE_FREESE_EN); 128*6352cd45SJagan Teki 129*6352cd45SJagan Teki /* enable DSI port */ 130*6352cd45SJagan Teki regmap_write(regmap, WR_DSI_PORT_EN, DSI_PORT_EN); 131*6352cd45SJagan Teki 132*6352cd45SJagan Teki memset(buf, 0, MAX_BYTE_SIZE); 133*6352cd45SJagan Teki 134*6352cd45SJagan Teki /* set image crop */ 135*6352cd45SJagan Teki buf[4] = mode->hdisplay & 0xff; 136*6352cd45SJagan Teki buf[5] = (mode->hdisplay & 0xff00) >> 8; 137*6352cd45SJagan Teki buf[6] = mode->vdisplay & 0xff; 138*6352cd45SJagan Teki buf[7] = (mode->vdisplay & 0xff00) >> 8; 139*6352cd45SJagan Teki regmap_noinc_write(regmap, WR_IMAGE_CROP, buf, MAX_BYTE_SIZE); 140*6352cd45SJagan Teki 141*6352cd45SJagan Teki /* set display size */ 142*6352cd45SJagan Teki buf[4] = mode->hdisplay & 0xff; 143*6352cd45SJagan Teki buf[5] = (mode->hdisplay & 0xff00) >> 8; 144*6352cd45SJagan Teki buf[6] = mode->vdisplay & 0xff; 145*6352cd45SJagan Teki buf[7] = (mode->vdisplay & 0xff00) >> 8; 146*6352cd45SJagan Teki regmap_noinc_write(regmap, WR_DISPLAY_SIZE, buf, MAX_BYTE_SIZE); 147*6352cd45SJagan Teki 148*6352cd45SJagan Teki /* set input image size */ 149*6352cd45SJagan Teki buf[0] = mode->hdisplay & 0xff; 150*6352cd45SJagan Teki buf[1] = (mode->hdisplay & 0xff00) >> 8; 151*6352cd45SJagan Teki buf[2] = mode->vdisplay & 0xff; 152*6352cd45SJagan Teki buf[3] = (mode->vdisplay & 0xff00) >> 8; 153*6352cd45SJagan Teki regmap_noinc_write(regmap, WR_INPUT_IMAGE_SIZE, buf, 4); 154*6352cd45SJagan Teki 155*6352cd45SJagan Teki /* set external video port */ 156*6352cd45SJagan Teki regmap_write(regmap, WR_INPUT_SOURCE, INPUT_EXTERNAL_VIDEO); 157*6352cd45SJagan Teki 158*6352cd45SJagan Teki /* set external video format select as DSI */ 159*6352cd45SJagan Teki regmap_write(regmap, WR_EXT_SOURCE_FMT, EXT_SOURCE_FMT_DSI); 160*6352cd45SJagan Teki 161*6352cd45SJagan Teki /* disable image freeze */ 162*6352cd45SJagan Teki regmap_write(regmap, WR_IMAGE_FREEZE, 0x00); 163*6352cd45SJagan Teki 164*6352cd45SJagan Teki /* enable RGB led */ 165*6352cd45SJagan Teki regmap_update_bits(regmap, WR_RGB_LED_EN, LED_MASK, 166*6352cd45SJagan Teki RED_LED_EN | GREEN_LED_EN | BLUE_LED_EN); 167*6352cd45SJagan Teki 168*6352cd45SJagan Teki msleep(10); 169*6352cd45SJagan Teki } 170*6352cd45SJagan Teki 171*6352cd45SJagan Teki static void dlpc_atomic_pre_enable(struct drm_bridge *bridge, 172*6352cd45SJagan Teki struct drm_bridge_state *old_bridge_state) 173*6352cd45SJagan Teki { 174*6352cd45SJagan Teki struct dlpc *dlpc = bridge_to_dlpc(bridge); 175*6352cd45SJagan Teki int ret; 176*6352cd45SJagan Teki 177*6352cd45SJagan Teki gpiod_set_value(dlpc->enable_gpio, 1); 178*6352cd45SJagan Teki 179*6352cd45SJagan Teki msleep(500); 180*6352cd45SJagan Teki 181*6352cd45SJagan Teki ret = regulator_enable(dlpc->vcc_intf); 182*6352cd45SJagan Teki if (ret) 183*6352cd45SJagan Teki DRM_DEV_ERROR(dlpc->dev, 184*6352cd45SJagan Teki "failed to enable VCC_INTF regulator: %d\n", ret); 185*6352cd45SJagan Teki 186*6352cd45SJagan Teki ret = regulator_enable(dlpc->vcc_flsh); 187*6352cd45SJagan Teki if (ret) 188*6352cd45SJagan Teki DRM_DEV_ERROR(dlpc->dev, 189*6352cd45SJagan Teki "failed to enable VCC_FLSH regulator: %d\n", ret); 190*6352cd45SJagan Teki 191*6352cd45SJagan Teki msleep(10); 192*6352cd45SJagan Teki } 193*6352cd45SJagan Teki 194*6352cd45SJagan Teki static void dlpc_atomic_post_disable(struct drm_bridge *bridge, 195*6352cd45SJagan Teki struct drm_bridge_state *old_bridge_state) 196*6352cd45SJagan Teki { 197*6352cd45SJagan Teki struct dlpc *dlpc = bridge_to_dlpc(bridge); 198*6352cd45SJagan Teki 199*6352cd45SJagan Teki regulator_disable(dlpc->vcc_flsh); 200*6352cd45SJagan Teki regulator_disable(dlpc->vcc_intf); 201*6352cd45SJagan Teki 202*6352cd45SJagan Teki msleep(10); 203*6352cd45SJagan Teki 204*6352cd45SJagan Teki gpiod_set_value(dlpc->enable_gpio, 0); 205*6352cd45SJagan Teki 206*6352cd45SJagan Teki msleep(500); 207*6352cd45SJagan Teki } 208*6352cd45SJagan Teki 209*6352cd45SJagan Teki #define MAX_INPUT_SEL_FORMATS 1 210*6352cd45SJagan Teki 211*6352cd45SJagan Teki static u32 * 212*6352cd45SJagan Teki dlpc_atomic_get_input_bus_fmts(struct drm_bridge *bridge, 213*6352cd45SJagan Teki struct drm_bridge_state *bridge_state, 214*6352cd45SJagan Teki struct drm_crtc_state *crtc_state, 215*6352cd45SJagan Teki struct drm_connector_state *conn_state, 216*6352cd45SJagan Teki u32 output_fmt, 217*6352cd45SJagan Teki unsigned int *num_input_fmts) 218*6352cd45SJagan Teki { 219*6352cd45SJagan Teki u32 *input_fmts; 220*6352cd45SJagan Teki 221*6352cd45SJagan Teki *num_input_fmts = 0; 222*6352cd45SJagan Teki 223*6352cd45SJagan Teki input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts), 224*6352cd45SJagan Teki GFP_KERNEL); 225*6352cd45SJagan Teki if (!input_fmts) 226*6352cd45SJagan Teki return NULL; 227*6352cd45SJagan Teki 228*6352cd45SJagan Teki /* This is the DSI-end bus format */ 229*6352cd45SJagan Teki input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; 230*6352cd45SJagan Teki *num_input_fmts = 1; 231*6352cd45SJagan Teki 232*6352cd45SJagan Teki return input_fmts; 233*6352cd45SJagan Teki } 234*6352cd45SJagan Teki 235*6352cd45SJagan Teki static void dlpc_mode_set(struct drm_bridge *bridge, 236*6352cd45SJagan Teki const struct drm_display_mode *mode, 237*6352cd45SJagan Teki const struct drm_display_mode *adjusted_mode) 238*6352cd45SJagan Teki { 239*6352cd45SJagan Teki struct dlpc *dlpc = bridge_to_dlpc(bridge); 240*6352cd45SJagan Teki 241*6352cd45SJagan Teki drm_mode_copy(&dlpc->mode, adjusted_mode); 242*6352cd45SJagan Teki } 243*6352cd45SJagan Teki 244*6352cd45SJagan Teki static int dlpc_attach(struct drm_bridge *bridge, 245*6352cd45SJagan Teki enum drm_bridge_attach_flags flags) 246*6352cd45SJagan Teki { 247*6352cd45SJagan Teki struct dlpc *dlpc = bridge_to_dlpc(bridge); 248*6352cd45SJagan Teki 249*6352cd45SJagan Teki return drm_bridge_attach(bridge->encoder, dlpc->next_bridge, bridge, flags); 250*6352cd45SJagan Teki } 251*6352cd45SJagan Teki 252*6352cd45SJagan Teki static const struct drm_bridge_funcs dlpc_bridge_funcs = { 253*6352cd45SJagan Teki .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 254*6352cd45SJagan Teki .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 255*6352cd45SJagan Teki .atomic_get_input_bus_fmts = dlpc_atomic_get_input_bus_fmts, 256*6352cd45SJagan Teki .atomic_reset = drm_atomic_helper_bridge_reset, 257*6352cd45SJagan Teki .atomic_pre_enable = dlpc_atomic_pre_enable, 258*6352cd45SJagan Teki .atomic_enable = dlpc_atomic_enable, 259*6352cd45SJagan Teki .atomic_post_disable = dlpc_atomic_post_disable, 260*6352cd45SJagan Teki .mode_set = dlpc_mode_set, 261*6352cd45SJagan Teki .attach = dlpc_attach, 262*6352cd45SJagan Teki }; 263*6352cd45SJagan Teki 264*6352cd45SJagan Teki static int dlpc3433_parse_dt(struct dlpc *dlpc) 265*6352cd45SJagan Teki { 266*6352cd45SJagan Teki struct device *dev = dlpc->dev; 267*6352cd45SJagan Teki struct device_node *endpoint; 268*6352cd45SJagan Teki int ret; 269*6352cd45SJagan Teki 270*6352cd45SJagan Teki dlpc->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 271*6352cd45SJagan Teki if (IS_ERR(dlpc->enable_gpio)) 272*6352cd45SJagan Teki return PTR_ERR(dlpc->enable_gpio); 273*6352cd45SJagan Teki 274*6352cd45SJagan Teki dlpc->vcc_intf = devm_regulator_get(dlpc->dev, "vcc_intf"); 275*6352cd45SJagan Teki if (IS_ERR(dlpc->vcc_intf)) 276*6352cd45SJagan Teki return dev_err_probe(dev, PTR_ERR(dlpc->vcc_intf), 277*6352cd45SJagan Teki "failed to get VCC_INTF supply\n"); 278*6352cd45SJagan Teki 279*6352cd45SJagan Teki dlpc->vcc_flsh = devm_regulator_get(dlpc->dev, "vcc_flsh"); 280*6352cd45SJagan Teki if (IS_ERR(dlpc->vcc_flsh)) 281*6352cd45SJagan Teki return dev_err_probe(dev, PTR_ERR(dlpc->vcc_flsh), 282*6352cd45SJagan Teki "failed to get VCC_FLSH supply\n"); 283*6352cd45SJagan Teki 284*6352cd45SJagan Teki dlpc->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); 285*6352cd45SJagan Teki if (IS_ERR(dlpc->next_bridge)) 286*6352cd45SJagan Teki return PTR_ERR(dlpc->next_bridge); 287*6352cd45SJagan Teki 288*6352cd45SJagan Teki endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0); 289*6352cd45SJagan Teki dlpc->dsi_lanes = of_property_count_u32_elems(endpoint, "data-lanes"); 290*6352cd45SJagan Teki if (dlpc->dsi_lanes < 0 || dlpc->dsi_lanes > 4) { 291*6352cd45SJagan Teki ret = -EINVAL; 292*6352cd45SJagan Teki goto err_put_endpoint; 293*6352cd45SJagan Teki } 294*6352cd45SJagan Teki 295*6352cd45SJagan Teki dlpc->host_node = of_graph_get_remote_port_parent(endpoint); 296*6352cd45SJagan Teki if (!dlpc->host_node) { 297*6352cd45SJagan Teki ret = -ENODEV; 298*6352cd45SJagan Teki goto err_put_host; 299*6352cd45SJagan Teki } 300*6352cd45SJagan Teki 301*6352cd45SJagan Teki of_node_put(endpoint); 302*6352cd45SJagan Teki 303*6352cd45SJagan Teki return 0; 304*6352cd45SJagan Teki 305*6352cd45SJagan Teki err_put_host: 306*6352cd45SJagan Teki of_node_put(dlpc->host_node); 307*6352cd45SJagan Teki err_put_endpoint: 308*6352cd45SJagan Teki of_node_put(endpoint); 309*6352cd45SJagan Teki return ret; 310*6352cd45SJagan Teki } 311*6352cd45SJagan Teki 312*6352cd45SJagan Teki static int dlpc_host_attach(struct dlpc *dlpc) 313*6352cd45SJagan Teki { 314*6352cd45SJagan Teki struct device *dev = dlpc->dev; 315*6352cd45SJagan Teki struct mipi_dsi_host *host; 316*6352cd45SJagan Teki struct mipi_dsi_device_info info = { 317*6352cd45SJagan Teki .type = "dlpc3433", 318*6352cd45SJagan Teki .channel = 0, 319*6352cd45SJagan Teki .node = NULL, 320*6352cd45SJagan Teki }; 321*6352cd45SJagan Teki 322*6352cd45SJagan Teki host = of_find_mipi_dsi_host_by_node(dlpc->host_node); 323*6352cd45SJagan Teki if (!host) { 324*6352cd45SJagan Teki DRM_DEV_ERROR(dev, "failed to find dsi host\n"); 325*6352cd45SJagan Teki return -EPROBE_DEFER; 326*6352cd45SJagan Teki } 327*6352cd45SJagan Teki 328*6352cd45SJagan Teki dlpc->dsi = mipi_dsi_device_register_full(host, &info); 329*6352cd45SJagan Teki if (IS_ERR(dlpc->dsi)) { 330*6352cd45SJagan Teki DRM_DEV_ERROR(dev, "failed to create dsi device\n"); 331*6352cd45SJagan Teki return PTR_ERR(dlpc->dsi); 332*6352cd45SJagan Teki } 333*6352cd45SJagan Teki 334*6352cd45SJagan Teki dlpc->dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST; 335*6352cd45SJagan Teki dlpc->dsi->format = MIPI_DSI_FMT_RGB565; 336*6352cd45SJagan Teki dlpc->dsi->lanes = dlpc->dsi_lanes; 337*6352cd45SJagan Teki 338*6352cd45SJagan Teki return devm_mipi_dsi_attach(dev, dlpc->dsi); 339*6352cd45SJagan Teki } 340*6352cd45SJagan Teki 341*6352cd45SJagan Teki static int dlpc3433_probe(struct i2c_client *client) 342*6352cd45SJagan Teki { 343*6352cd45SJagan Teki struct device *dev = &client->dev; 344*6352cd45SJagan Teki struct dlpc *dlpc; 345*6352cd45SJagan Teki int ret; 346*6352cd45SJagan Teki 347*6352cd45SJagan Teki dlpc = devm_kzalloc(dev, sizeof(*dlpc), GFP_KERNEL); 348*6352cd45SJagan Teki if (!dlpc) 349*6352cd45SJagan Teki return -ENOMEM; 350*6352cd45SJagan Teki 351*6352cd45SJagan Teki dlpc->dev = dev; 352*6352cd45SJagan Teki 353*6352cd45SJagan Teki dlpc->regmap = devm_regmap_init_i2c(client, &dlpc_regmap_config); 354*6352cd45SJagan Teki if (IS_ERR(dlpc->regmap)) 355*6352cd45SJagan Teki return PTR_ERR(dlpc->regmap); 356*6352cd45SJagan Teki 357*6352cd45SJagan Teki ret = dlpc3433_parse_dt(dlpc); 358*6352cd45SJagan Teki if (ret) 359*6352cd45SJagan Teki return ret; 360*6352cd45SJagan Teki 361*6352cd45SJagan Teki dev_set_drvdata(dev, dlpc); 362*6352cd45SJagan Teki i2c_set_clientdata(client, dlpc); 363*6352cd45SJagan Teki 364*6352cd45SJagan Teki dlpc->bridge.funcs = &dlpc_bridge_funcs; 365*6352cd45SJagan Teki dlpc->bridge.of_node = dev->of_node; 366*6352cd45SJagan Teki drm_bridge_add(&dlpc->bridge); 367*6352cd45SJagan Teki 368*6352cd45SJagan Teki ret = dlpc_host_attach(dlpc); 369*6352cd45SJagan Teki if (ret) { 370*6352cd45SJagan Teki DRM_DEV_ERROR(dev, "failed to attach dsi host\n"); 371*6352cd45SJagan Teki goto err_remove_bridge; 372*6352cd45SJagan Teki } 373*6352cd45SJagan Teki 374*6352cd45SJagan Teki return 0; 375*6352cd45SJagan Teki 376*6352cd45SJagan Teki err_remove_bridge: 377*6352cd45SJagan Teki drm_bridge_remove(&dlpc->bridge); 378*6352cd45SJagan Teki return ret; 379*6352cd45SJagan Teki } 380*6352cd45SJagan Teki 381*6352cd45SJagan Teki static int dlpc3433_remove(struct i2c_client *client) 382*6352cd45SJagan Teki { 383*6352cd45SJagan Teki struct dlpc *dlpc = i2c_get_clientdata(client); 384*6352cd45SJagan Teki 385*6352cd45SJagan Teki drm_bridge_remove(&dlpc->bridge); 386*6352cd45SJagan Teki of_node_put(dlpc->host_node); 387*6352cd45SJagan Teki 388*6352cd45SJagan Teki return 0; 389*6352cd45SJagan Teki } 390*6352cd45SJagan Teki 391*6352cd45SJagan Teki static const struct i2c_device_id dlpc3433_id[] = { 392*6352cd45SJagan Teki { "ti,dlpc3433", 0 }, 393*6352cd45SJagan Teki { /* sentinel */ } 394*6352cd45SJagan Teki }; 395*6352cd45SJagan Teki MODULE_DEVICE_TABLE(i2c, dlpc3433_id); 396*6352cd45SJagan Teki 397*6352cd45SJagan Teki static const struct of_device_id dlpc3433_match_table[] = { 398*6352cd45SJagan Teki { .compatible = "ti,dlpc3433" }, 399*6352cd45SJagan Teki { /* sentinel */ } 400*6352cd45SJagan Teki }; 401*6352cd45SJagan Teki MODULE_DEVICE_TABLE(of, dlpc3433_match_table); 402*6352cd45SJagan Teki 403*6352cd45SJagan Teki static struct i2c_driver dlpc3433_driver = { 404*6352cd45SJagan Teki .probe_new = dlpc3433_probe, 405*6352cd45SJagan Teki .remove = dlpc3433_remove, 406*6352cd45SJagan Teki .id_table = dlpc3433_id, 407*6352cd45SJagan Teki .driver = { 408*6352cd45SJagan Teki .name = "ti-dlpc3433", 409*6352cd45SJagan Teki .of_match_table = dlpc3433_match_table, 410*6352cd45SJagan Teki }, 411*6352cd45SJagan Teki }; 412*6352cd45SJagan Teki module_i2c_driver(dlpc3433_driver); 413*6352cd45SJagan Teki 414*6352cd45SJagan Teki MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>"); 415*6352cd45SJagan Teki MODULE_AUTHOR("Christopher Vollo <chris@renewoutreach.org>"); 416*6352cd45SJagan Teki MODULE_DESCRIPTION("TI DLPC3433 MIPI DSI Display Controller Bridge"); 417*6352cd45SJagan Teki MODULE_LICENSE("GPL"); 418