linux/drivers/gpu/drm/bridge/chipone-icn6211.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2020 Amarula Solutions(India)
   4 * Author: Jagan Teki <jagan@amarulasolutions.com>
   5 */
   6
   7#include <drm/drm_of.h>
   8#include <drm/drm_print.h>
   9#include <drm/drm_mipi_dsi.h>
  10
  11#include <linux/delay.h>
  12#include <linux/gpio/consumer.h>
  13#include <linux/module.h>
  14#include <linux/of_device.h>
  15#include <linux/regulator/consumer.h>
  16
  17#include <video/mipi_display.h>
  18
  19#define HACTIVE_LI              0x20
  20#define VACTIVE_LI              0x21
  21#define VACTIVE_HACTIVE_HI      0x22
  22#define HFP_LI                  0x23
  23#define HSYNC_LI                0x24
  24#define HBP_LI                  0x25
  25#define HFP_HSW_HBP_HI          0x26
  26#define VFP                     0x27
  27#define VSYNC                   0x28
  28#define VBP                     0x29
  29
  30struct chipone {
  31        struct device *dev;
  32        struct drm_bridge bridge;
  33        struct drm_bridge *panel_bridge;
  34        struct gpio_desc *enable_gpio;
  35        struct regulator *vdd1;
  36        struct regulator *vdd2;
  37        struct regulator *vdd3;
  38};
  39
  40static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge)
  41{
  42        return container_of(bridge, struct chipone, bridge);
  43}
  44
  45static struct drm_display_mode *bridge_to_mode(struct drm_bridge *bridge)
  46{
  47        return &bridge->encoder->crtc->state->adjusted_mode;
  48}
  49
  50static inline int chipone_dsi_write(struct chipone *icn,  const void *seq,
  51                                    size_t len)
  52{
  53        struct mipi_dsi_device *dsi = to_mipi_dsi_device(icn->dev);
  54
  55        return mipi_dsi_generic_write(dsi, seq, len);
  56}
  57
  58#define ICN6211_DSI(icn, seq...)                                \
  59        {                                                       \
  60                const u8 d[] = { seq };                         \
  61                chipone_dsi_write(icn, d, ARRAY_SIZE(d));       \
  62        }
  63
  64static void chipone_enable(struct drm_bridge *bridge)
  65{
  66        struct chipone *icn = bridge_to_chipone(bridge);
  67        struct drm_display_mode *mode = bridge_to_mode(bridge);
  68
  69        ICN6211_DSI(icn, 0x7a, 0xc1);
  70
  71        ICN6211_DSI(icn, HACTIVE_LI, mode->hdisplay & 0xff);
  72
  73        ICN6211_DSI(icn, VACTIVE_LI, mode->vdisplay & 0xff);
  74
  75        /**
  76         * lsb nibble: 2nd nibble of hdisplay
  77         * msb nibble: 2nd nibble of vdisplay
  78         */
  79        ICN6211_DSI(icn, VACTIVE_HACTIVE_HI,
  80                    ((mode->hdisplay >> 8) & 0xf) |
  81                    (((mode->vdisplay >> 8) & 0xf) << 4));
  82
  83        ICN6211_DSI(icn, HFP_LI, mode->hsync_start - mode->hdisplay);
  84
  85        ICN6211_DSI(icn, HSYNC_LI, mode->hsync_end - mode->hsync_start);
  86
  87        ICN6211_DSI(icn, HBP_LI, mode->htotal - mode->hsync_end);
  88
  89        ICN6211_DSI(icn, HFP_HSW_HBP_HI, 0x00);
  90
  91        ICN6211_DSI(icn, VFP, mode->vsync_start - mode->vdisplay);
  92
  93        ICN6211_DSI(icn, VSYNC, mode->vsync_end - mode->vsync_start);
  94
  95        ICN6211_DSI(icn, VBP, mode->vtotal - mode->vsync_end);
  96
  97        /* dsi specific sequence */
  98        ICN6211_DSI(icn, MIPI_DCS_SET_TEAR_OFF, 0x80);
  99        ICN6211_DSI(icn, MIPI_DCS_SET_ADDRESS_MODE, 0x28);
 100        ICN6211_DSI(icn, 0xb5, 0xa0);
 101        ICN6211_DSI(icn, 0x5c, 0xff);
 102        ICN6211_DSI(icn, MIPI_DCS_SET_COLUMN_ADDRESS, 0x01);
 103        ICN6211_DSI(icn, MIPI_DCS_GET_POWER_SAVE, 0x92);
 104        ICN6211_DSI(icn, 0x6b, 0x71);
 105        ICN6211_DSI(icn, 0x69, 0x2b);
 106        ICN6211_DSI(icn, MIPI_DCS_ENTER_SLEEP_MODE, 0x40);
 107        ICN6211_DSI(icn, MIPI_DCS_EXIT_SLEEP_MODE, 0x98);
 108
 109        /* icn6211 specific sequence */
 110        ICN6211_DSI(icn, 0xb6, 0x20);
 111        ICN6211_DSI(icn, 0x51, 0x20);
 112        ICN6211_DSI(icn, 0x09, 0x10);
 113
 114        usleep_range(10000, 11000);
 115}
 116
 117static void chipone_pre_enable(struct drm_bridge *bridge)
 118{
 119        struct chipone *icn = bridge_to_chipone(bridge);
 120        int ret;
 121
 122        if (icn->vdd1) {
 123                ret = regulator_enable(icn->vdd1);
 124                if (ret)
 125                        DRM_DEV_ERROR(icn->dev,
 126                                      "failed to enable VDD1 regulator: %d\n", ret);
 127        }
 128
 129        if (icn->vdd2) {
 130                ret = regulator_enable(icn->vdd2);
 131                if (ret)
 132                        DRM_DEV_ERROR(icn->dev,
 133                                      "failed to enable VDD2 regulator: %d\n", ret);
 134        }
 135
 136        if (icn->vdd3) {
 137                ret = regulator_enable(icn->vdd3);
 138                if (ret)
 139                        DRM_DEV_ERROR(icn->dev,
 140                                      "failed to enable VDD3 regulator: %d\n", ret);
 141        }
 142
 143        gpiod_set_value(icn->enable_gpio, 1);
 144
 145        usleep_range(10000, 11000);
 146}
 147
 148static void chipone_post_disable(struct drm_bridge *bridge)
 149{
 150        struct chipone *icn = bridge_to_chipone(bridge);
 151
 152        if (icn->vdd1)
 153                regulator_disable(icn->vdd1);
 154
 155        if (icn->vdd2)
 156                regulator_disable(icn->vdd2);
 157
 158        if (icn->vdd3)
 159                regulator_disable(icn->vdd3);
 160
 161        gpiod_set_value(icn->enable_gpio, 0);
 162}
 163
 164static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
 165{
 166        struct chipone *icn = bridge_to_chipone(bridge);
 167
 168        return drm_bridge_attach(bridge->encoder, icn->panel_bridge, bridge, flags);
 169}
 170
 171static const struct drm_bridge_funcs chipone_bridge_funcs = {
 172        .attach = chipone_attach,
 173        .post_disable = chipone_post_disable,
 174        .pre_enable = chipone_pre_enable,
 175        .enable = chipone_enable,
 176};
 177
 178static int chipone_parse_dt(struct chipone *icn)
 179{
 180        struct device *dev = icn->dev;
 181        struct drm_panel *panel;
 182        int ret;
 183
 184        icn->vdd1 = devm_regulator_get_optional(dev, "vdd1");
 185        if (IS_ERR(icn->vdd1)) {
 186                ret = PTR_ERR(icn->vdd1);
 187                if (ret == -EPROBE_DEFER)
 188                        return -EPROBE_DEFER;
 189                icn->vdd1 = NULL;
 190                DRM_DEV_DEBUG(dev, "failed to get VDD1 regulator: %d\n", ret);
 191        }
 192
 193        icn->vdd2 = devm_regulator_get_optional(dev, "vdd2");
 194        if (IS_ERR(icn->vdd2)) {
 195                ret = PTR_ERR(icn->vdd2);
 196                if (ret == -EPROBE_DEFER)
 197                        return -EPROBE_DEFER;
 198                icn->vdd2 = NULL;
 199                DRM_DEV_DEBUG(dev, "failed to get VDD2 regulator: %d\n", ret);
 200        }
 201
 202        icn->vdd3 = devm_regulator_get_optional(dev, "vdd3");
 203        if (IS_ERR(icn->vdd3)) {
 204                ret = PTR_ERR(icn->vdd3);
 205                if (ret == -EPROBE_DEFER)
 206                        return -EPROBE_DEFER;
 207                icn->vdd3 = NULL;
 208                DRM_DEV_DEBUG(dev, "failed to get VDD3 regulator: %d\n", ret);
 209        }
 210
 211        icn->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
 212        if (IS_ERR(icn->enable_gpio)) {
 213                DRM_DEV_ERROR(dev, "failed to get enable GPIO\n");
 214                return PTR_ERR(icn->enable_gpio);
 215        }
 216
 217        ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL);
 218        if (ret)
 219                return ret;
 220
 221        icn->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
 222        if (IS_ERR(icn->panel_bridge))
 223                return PTR_ERR(icn->panel_bridge);
 224
 225        return 0;
 226}
 227
 228static int chipone_probe(struct mipi_dsi_device *dsi)
 229{
 230        struct device *dev = &dsi->dev;
 231        struct chipone *icn;
 232        int ret;
 233
 234        icn = devm_kzalloc(dev, sizeof(struct chipone), GFP_KERNEL);
 235        if (!icn)
 236                return -ENOMEM;
 237
 238        mipi_dsi_set_drvdata(dsi, icn);
 239        icn->dev = dev;
 240
 241        ret = chipone_parse_dt(icn);
 242        if (ret)
 243                return ret;
 244
 245        icn->bridge.funcs = &chipone_bridge_funcs;
 246        icn->bridge.type = DRM_MODE_CONNECTOR_DPI;
 247        icn->bridge.of_node = dev->of_node;
 248
 249        drm_bridge_add(&icn->bridge);
 250
 251        dsi->lanes = 4;
 252        dsi->format = MIPI_DSI_FMT_RGB888;
 253        dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
 254
 255        ret = mipi_dsi_attach(dsi);
 256        if (ret < 0) {
 257                drm_bridge_remove(&icn->bridge);
 258                dev_err(dev, "failed to attach dsi\n");
 259        }
 260
 261        return ret;
 262}
 263
 264static int chipone_remove(struct mipi_dsi_device *dsi)
 265{
 266        struct chipone *icn = mipi_dsi_get_drvdata(dsi);
 267
 268        mipi_dsi_detach(dsi);
 269        drm_bridge_remove(&icn->bridge);
 270
 271        return 0;
 272}
 273
 274static const struct of_device_id chipone_of_match[] = {
 275        { .compatible = "chipone,icn6211", },
 276        { /* sentinel */ }
 277};
 278MODULE_DEVICE_TABLE(of, chipone_of_match);
 279
 280static struct mipi_dsi_driver chipone_driver = {
 281        .probe = chipone_probe,
 282        .remove = chipone_remove,
 283        .driver = {
 284                .name = "chipone-icn6211",
 285                .owner = THIS_MODULE,
 286                .of_match_table = chipone_of_match,
 287        },
 288};
 289module_mipi_dsi_driver(chipone_driver);
 290
 291MODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>");
 292MODULE_DESCRIPTION("Chipone ICN6211 MIPI-DSI to RGB Converter Bridge");
 293MODULE_LICENSE("GPL");
 294