Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (C) 2021 RenewOutReach
0004  * Copyright (C) 2021 Amarula Solutions(India)
0005  *
0006  * Author:
0007  * Jagan Teki <jagan@amarulasolutions.com>
0008  * Christopher Vollo <chris@renewoutreach.org>
0009  */
0010 
0011 #include <drm/drm_atomic_helper.h>
0012 #include <drm/drm_of.h>
0013 #include <drm/drm_print.h>
0014 #include <drm/drm_mipi_dsi.h>
0015 
0016 #include <linux/delay.h>
0017 #include <linux/gpio/consumer.h>
0018 #include <linux/i2c.h>
0019 #include <linux/media-bus-format.h>
0020 #include <linux/module.h>
0021 #include <linux/regmap.h>
0022 #include <linux/regulator/consumer.h>
0023 
0024 enum cmd_registers {
0025     WR_INPUT_SOURCE     = 0x05, /* Write Input Source Select */
0026     WR_EXT_SOURCE_FMT   = 0x07, /* Write External Video Source Format */
0027     WR_IMAGE_CROP       = 0x10, /* Write Image Crop */
0028     WR_DISPLAY_SIZE     = 0x12, /* Write Display Size */
0029     WR_IMAGE_FREEZE     = 0x1A, /* Write Image Freeze */
0030     WR_INPUT_IMAGE_SIZE = 0x2E, /* Write External Input Image Size */
0031     WR_RGB_LED_EN       = 0x52, /* Write RGB LED Enable */
0032     WR_RGB_LED_CURRENT  = 0x54, /* Write RGB LED Current */
0033     WR_RGB_LED_MAX_CURRENT  = 0x5C, /* Write RGB LED Max Current */
0034     WR_DSI_HS_CLK       = 0xBD, /* Write DSI HS Clock */
0035     RD_DEVICE_ID        = 0xD4, /* Read Controller Device ID */
0036     WR_DSI_PORT_EN      = 0xD7, /* Write DSI Port Enable */
0037 };
0038 
0039 enum input_source {
0040     INPUT_EXTERNAL_VIDEO    = 0,
0041     INPUT_TEST_PATTERN,
0042     INPUT_SPLASH_SCREEN,
0043 };
0044 
0045 #define DEV_ID_MASK     GENMASK(3, 0)
0046 #define IMAGE_FREESE_EN     BIT(0)
0047 #define DSI_PORT_EN     0
0048 #define EXT_SOURCE_FMT_DSI  0
0049 #define RED_LED_EN      BIT(0)
0050 #define GREEN_LED_EN        BIT(1)
0051 #define BLUE_LED_EN     BIT(2)
0052 #define LED_MASK        GENMASK(2, 0)
0053 #define MAX_BYTE_SIZE       8
0054 
0055 struct dlpc {
0056     struct device       *dev;
0057     struct drm_bridge   bridge;
0058     struct drm_bridge   *next_bridge;
0059     struct device_node  *host_node;
0060     struct mipi_dsi_device  *dsi;
0061     struct drm_display_mode mode;
0062 
0063     struct gpio_desc    *enable_gpio;
0064     struct regulator    *vcc_intf;
0065     struct regulator    *vcc_flsh;
0066     struct regmap       *regmap;
0067     unsigned int        dsi_lanes;
0068 };
0069 
0070 static inline struct dlpc *bridge_to_dlpc(struct drm_bridge *bridge)
0071 {
0072     return container_of(bridge, struct dlpc, bridge);
0073 }
0074 
0075 static bool dlpc_writeable_noinc_reg(struct device *dev, unsigned int reg)
0076 {
0077     switch (reg) {
0078     case WR_IMAGE_CROP:
0079     case WR_DISPLAY_SIZE:
0080     case WR_INPUT_IMAGE_SIZE:
0081     case WR_DSI_HS_CLK:
0082         return true;
0083     default:
0084         return false;
0085     }
0086 }
0087 
0088 static const struct regmap_range dlpc_volatile_ranges[] = {
0089     { .range_min = 0x10, .range_max = 0xBF },
0090 };
0091 
0092 static const struct regmap_access_table dlpc_volatile_table = {
0093     .yes_ranges = dlpc_volatile_ranges,
0094     .n_yes_ranges = ARRAY_SIZE(dlpc_volatile_ranges),
0095 };
0096 
0097 static struct regmap_config dlpc_regmap_config = {
0098     .reg_bits       = 8,
0099     .val_bits       = 8,
0100     .max_register       = WR_DSI_PORT_EN,
0101     .writeable_noinc_reg    = dlpc_writeable_noinc_reg,
0102     .volatile_table     = &dlpc_volatile_table,
0103     .cache_type     = REGCACHE_RBTREE,
0104     .name           = "dlpc3433",
0105 };
0106 
0107 static void dlpc_atomic_enable(struct drm_bridge *bridge,
0108                    struct drm_bridge_state *old_bridge_state)
0109 {
0110     struct dlpc *dlpc = bridge_to_dlpc(bridge);
0111     struct device *dev = dlpc->dev;
0112     struct drm_display_mode *mode = &dlpc->mode;
0113     struct regmap *regmap = dlpc->regmap;
0114     char buf[MAX_BYTE_SIZE];
0115     unsigned int devid;
0116 
0117     regmap_read(regmap, RD_DEVICE_ID, &devid);
0118     devid &= DEV_ID_MASK;
0119 
0120     DRM_DEV_DEBUG(dev, "DLPC3433 device id: 0x%02x\n", devid);
0121 
0122     if (devid != 0x01) {
0123         DRM_DEV_ERROR(dev, "Unsupported DLPC device id: 0x%02x\n", devid);
0124         return;
0125     }
0126 
0127     /* disable image freeze */
0128     regmap_write(regmap, WR_IMAGE_FREEZE, IMAGE_FREESE_EN);
0129 
0130     /* enable DSI port */
0131     regmap_write(regmap, WR_DSI_PORT_EN, DSI_PORT_EN);
0132 
0133     memset(buf, 0, MAX_BYTE_SIZE);
0134 
0135     /* set image crop */
0136     buf[4] = mode->hdisplay & 0xff;
0137     buf[5] = (mode->hdisplay & 0xff00) >> 8;
0138     buf[6] = mode->vdisplay & 0xff;
0139     buf[7] = (mode->vdisplay & 0xff00) >> 8;
0140     regmap_noinc_write(regmap, WR_IMAGE_CROP, buf, MAX_BYTE_SIZE);
0141 
0142     /* set display size */
0143     buf[4] = mode->hdisplay & 0xff;
0144     buf[5] = (mode->hdisplay & 0xff00) >> 8;
0145     buf[6] = mode->vdisplay & 0xff;
0146     buf[7] = (mode->vdisplay & 0xff00) >> 8;
0147     regmap_noinc_write(regmap, WR_DISPLAY_SIZE, buf, MAX_BYTE_SIZE);
0148 
0149     /* set input image size */
0150     buf[0] = mode->hdisplay & 0xff;
0151     buf[1] = (mode->hdisplay & 0xff00) >> 8;
0152     buf[2] = mode->vdisplay & 0xff;
0153     buf[3] = (mode->vdisplay & 0xff00) >> 8;
0154     regmap_noinc_write(regmap, WR_INPUT_IMAGE_SIZE, buf, 4);
0155 
0156     /* set external video port */
0157     regmap_write(regmap, WR_INPUT_SOURCE, INPUT_EXTERNAL_VIDEO);
0158 
0159     /* set external video format select as DSI */
0160     regmap_write(regmap, WR_EXT_SOURCE_FMT, EXT_SOURCE_FMT_DSI);
0161 
0162     /* disable image freeze */
0163     regmap_write(regmap, WR_IMAGE_FREEZE, 0x00);
0164 
0165     /* enable RGB led */
0166     regmap_update_bits(regmap, WR_RGB_LED_EN, LED_MASK,
0167                RED_LED_EN | GREEN_LED_EN | BLUE_LED_EN);
0168 
0169     msleep(10);
0170 }
0171 
0172 static void dlpc_atomic_pre_enable(struct drm_bridge *bridge,
0173                    struct drm_bridge_state *old_bridge_state)
0174 {
0175     struct dlpc *dlpc = bridge_to_dlpc(bridge);
0176     int ret;
0177 
0178     gpiod_set_value(dlpc->enable_gpio, 1);
0179 
0180     msleep(500);
0181 
0182     ret = regulator_enable(dlpc->vcc_intf);
0183     if (ret)
0184         DRM_DEV_ERROR(dlpc->dev,
0185                   "failed to enable VCC_INTF regulator: %d\n", ret);
0186 
0187     ret = regulator_enable(dlpc->vcc_flsh);
0188     if (ret)
0189         DRM_DEV_ERROR(dlpc->dev,
0190                   "failed to enable VCC_FLSH regulator: %d\n", ret);
0191 
0192     msleep(10);
0193 }
0194 
0195 static void dlpc_atomic_post_disable(struct drm_bridge *bridge,
0196                      struct drm_bridge_state *old_bridge_state)
0197 {
0198     struct dlpc *dlpc = bridge_to_dlpc(bridge);
0199 
0200     regulator_disable(dlpc->vcc_flsh);
0201     regulator_disable(dlpc->vcc_intf);
0202 
0203     msleep(10);
0204 
0205     gpiod_set_value(dlpc->enable_gpio, 0);
0206 
0207     msleep(500);
0208 }
0209 
0210 #define MAX_INPUT_SEL_FORMATS   1
0211 
0212 static u32 *
0213 dlpc_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
0214                    struct drm_bridge_state *bridge_state,
0215                    struct drm_crtc_state *crtc_state,
0216                    struct drm_connector_state *conn_state,
0217                    u32 output_fmt,
0218                    unsigned int *num_input_fmts)
0219 {
0220     u32 *input_fmts;
0221 
0222     *num_input_fmts = 0;
0223 
0224     input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
0225                  GFP_KERNEL);
0226     if (!input_fmts)
0227         return NULL;
0228 
0229     /* This is the DSI-end bus format */
0230     input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
0231     *num_input_fmts = 1;
0232 
0233     return input_fmts;
0234 }
0235 
0236 static void dlpc_mode_set(struct drm_bridge *bridge,
0237               const struct drm_display_mode *mode,
0238               const struct drm_display_mode *adjusted_mode)
0239 {
0240     struct dlpc *dlpc = bridge_to_dlpc(bridge);
0241 
0242     drm_mode_copy(&dlpc->mode, adjusted_mode);
0243 }
0244 
0245 static int dlpc_attach(struct drm_bridge *bridge,
0246                enum drm_bridge_attach_flags flags)
0247 {
0248     struct dlpc *dlpc = bridge_to_dlpc(bridge);
0249 
0250     return drm_bridge_attach(bridge->encoder, dlpc->next_bridge, bridge, flags);
0251 }
0252 
0253 static const struct drm_bridge_funcs dlpc_bridge_funcs = {
0254     .atomic_duplicate_state     = drm_atomic_helper_bridge_duplicate_state,
0255     .atomic_destroy_state       = drm_atomic_helper_bridge_destroy_state,
0256     .atomic_get_input_bus_fmts  = dlpc_atomic_get_input_bus_fmts,
0257     .atomic_reset           = drm_atomic_helper_bridge_reset,
0258     .atomic_pre_enable      = dlpc_atomic_pre_enable,
0259     .atomic_enable          = dlpc_atomic_enable,
0260     .atomic_post_disable        = dlpc_atomic_post_disable,
0261     .mode_set           = dlpc_mode_set,
0262     .attach             = dlpc_attach,
0263 };
0264 
0265 static int dlpc3433_parse_dt(struct dlpc *dlpc)
0266 {
0267     struct device *dev = dlpc->dev;
0268     struct device_node *endpoint;
0269     int ret;
0270 
0271     dlpc->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
0272     if (IS_ERR(dlpc->enable_gpio))
0273         return PTR_ERR(dlpc->enable_gpio);
0274 
0275     dlpc->vcc_intf = devm_regulator_get(dlpc->dev, "vcc_intf");
0276     if (IS_ERR(dlpc->vcc_intf))
0277         return dev_err_probe(dev, PTR_ERR(dlpc->vcc_intf),
0278                      "failed to get VCC_INTF supply\n");
0279 
0280     dlpc->vcc_flsh = devm_regulator_get(dlpc->dev, "vcc_flsh");
0281     if (IS_ERR(dlpc->vcc_flsh))
0282         return dev_err_probe(dev, PTR_ERR(dlpc->vcc_flsh),
0283                      "failed to get VCC_FLSH supply\n");
0284 
0285     dlpc->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
0286     if (IS_ERR(dlpc->next_bridge))
0287         return PTR_ERR(dlpc->next_bridge);
0288 
0289     endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
0290     dlpc->dsi_lanes = of_property_count_u32_elems(endpoint, "data-lanes");
0291     if (dlpc->dsi_lanes < 0 || dlpc->dsi_lanes > 4) {
0292         ret = -EINVAL;
0293         goto err_put_endpoint;
0294     }
0295 
0296     dlpc->host_node = of_graph_get_remote_port_parent(endpoint);
0297     if (!dlpc->host_node) {
0298         ret = -ENODEV;
0299         goto err_put_host;
0300     }
0301 
0302     of_node_put(endpoint);
0303 
0304     return 0;
0305 
0306 err_put_host:
0307     of_node_put(dlpc->host_node);
0308 err_put_endpoint:
0309     of_node_put(endpoint);
0310     return ret;
0311 }
0312 
0313 static int dlpc_host_attach(struct dlpc *dlpc)
0314 {
0315     struct device *dev = dlpc->dev;
0316     struct mipi_dsi_host *host;
0317     struct mipi_dsi_device_info info = {
0318         .type = "dlpc3433",
0319         .channel = 0,
0320         .node = NULL,
0321     };
0322 
0323     host = of_find_mipi_dsi_host_by_node(dlpc->host_node);
0324     if (!host) {
0325         DRM_DEV_ERROR(dev, "failed to find dsi host\n");
0326         return -EPROBE_DEFER;
0327     }
0328 
0329     dlpc->dsi = mipi_dsi_device_register_full(host, &info);
0330     if (IS_ERR(dlpc->dsi)) {
0331         DRM_DEV_ERROR(dev, "failed to create dsi device\n");
0332         return PTR_ERR(dlpc->dsi);
0333     }
0334 
0335     dlpc->dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST;
0336     dlpc->dsi->format = MIPI_DSI_FMT_RGB565;
0337     dlpc->dsi->lanes = dlpc->dsi_lanes;
0338 
0339     return devm_mipi_dsi_attach(dev, dlpc->dsi);
0340 }
0341 
0342 static int dlpc3433_probe(struct i2c_client *client)
0343 {
0344     struct device *dev = &client->dev;
0345     struct dlpc *dlpc;
0346     int ret;
0347 
0348     dlpc = devm_kzalloc(dev, sizeof(*dlpc), GFP_KERNEL);
0349     if (!dlpc)
0350         return -ENOMEM;
0351 
0352     dlpc->dev = dev;
0353 
0354     dlpc->regmap = devm_regmap_init_i2c(client, &dlpc_regmap_config);
0355     if (IS_ERR(dlpc->regmap))
0356         return PTR_ERR(dlpc->regmap);
0357 
0358     ret = dlpc3433_parse_dt(dlpc);
0359     if (ret)
0360         return ret;
0361 
0362     dev_set_drvdata(dev, dlpc);
0363     i2c_set_clientdata(client, dlpc);
0364 
0365     dlpc->bridge.funcs = &dlpc_bridge_funcs;
0366     dlpc->bridge.of_node = dev->of_node;
0367     drm_bridge_add(&dlpc->bridge);
0368 
0369     ret = dlpc_host_attach(dlpc);
0370     if (ret) {
0371         DRM_DEV_ERROR(dev, "failed to attach dsi host\n");
0372         goto err_remove_bridge;
0373     }
0374 
0375     return 0;
0376 
0377 err_remove_bridge:
0378     drm_bridge_remove(&dlpc->bridge);
0379     return ret;
0380 }
0381 
0382 static int dlpc3433_remove(struct i2c_client *client)
0383 {
0384     struct dlpc *dlpc = i2c_get_clientdata(client);
0385 
0386     drm_bridge_remove(&dlpc->bridge);
0387     of_node_put(dlpc->host_node);
0388 
0389     return 0;
0390 }
0391 
0392 static const struct i2c_device_id dlpc3433_id[] = {
0393     { "ti,dlpc3433", 0 },
0394     { /* sentinel */ }
0395 };
0396 MODULE_DEVICE_TABLE(i2c, dlpc3433_id);
0397 
0398 static const struct of_device_id dlpc3433_match_table[] = {
0399     { .compatible = "ti,dlpc3433" },
0400     { /* sentinel */ }
0401 };
0402 MODULE_DEVICE_TABLE(of, dlpc3433_match_table);
0403 
0404 static struct i2c_driver dlpc3433_driver = {
0405     .probe_new = dlpc3433_probe,
0406     .remove = dlpc3433_remove,
0407     .id_table = dlpc3433_id,
0408     .driver = {
0409         .name = "ti-dlpc3433",
0410         .of_match_table = dlpc3433_match_table,
0411     },
0412 };
0413 module_i2c_driver(dlpc3433_driver);
0414 
0415 MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
0416 MODULE_AUTHOR("Christopher Vollo <chris@renewoutreach.org>");
0417 MODULE_DESCRIPTION("TI DLPC3433 MIPI DSI Display Controller Bridge");
0418 MODULE_LICENSE("GPL");