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