1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2022 Konrad Dybcio <konrad.dybcio@somainline.org> 4 * 5 * Generated with linux-mdss-dsi-panel-driver-generator with a 6 * substantial amount of manual adjustments. 7 * 8 * SONY Downstream kernel calls this one: 9 * - "JDI ID3" for Akari (XZ2) 10 * - "JDI ID4" for Apollo (XZ2 Compact) 11 */ 12 13 #include <linux/delay.h> 14 #include <linux/gpio/consumer.h> 15 #include <linux/module.h> 16 #include <linux/of.h> 17 #include <linux/regulator/consumer.h> 18 19 #include <video/mipi_display.h> 20 21 #include <drm/drm_mipi_dsi.h> 22 #include <drm/drm_modes.h> 23 #include <drm/drm_panel.h> 24 25 enum { 26 TYPE_TAMA_60HZ, 27 /* 28 * Leaving room for expansion - SONY very often uses 29 * *truly reliably* overclockable panels on their flagships! 30 */ 31 }; 32 33 struct sony_td4353_jdi { 34 struct drm_panel panel; 35 struct mipi_dsi_device *dsi; 36 struct regulator_bulk_data supplies[3]; 37 struct gpio_desc *panel_reset_gpio; 38 struct gpio_desc *touch_reset_gpio; 39 bool prepared; 40 int type; 41 }; 42 43 static inline struct sony_td4353_jdi *to_sony_td4353_jdi(struct drm_panel *panel) 44 { 45 return container_of(panel, struct sony_td4353_jdi, panel); 46 } 47 48 static int sony_td4353_jdi_on(struct sony_td4353_jdi *ctx) 49 { 50 struct mipi_dsi_device *dsi = ctx->dsi; 51 struct device *dev = &dsi->dev; 52 int ret; 53 54 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 55 56 ret = mipi_dsi_dcs_set_column_address(dsi, 0x0000, 1080 - 1); 57 if (ret < 0) { 58 dev_err(dev, "Failed to set column address: %d\n", ret); 59 return ret; 60 } 61 62 ret = mipi_dsi_dcs_set_page_address(dsi, 0x0000, 2160 - 1); 63 if (ret < 0) { 64 dev_err(dev, "Failed to set page address: %d\n", ret); 65 return ret; 66 } 67 68 ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0); 69 if (ret < 0) { 70 dev_err(dev, "Failed to set tear scanline: %d\n", ret); 71 return ret; 72 } 73 74 ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); 75 if (ret < 0) { 76 dev_err(dev, "Failed to set tear on: %d\n", ret); 77 return ret; 78 } 79 80 mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x00); 81 82 ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77); 83 if (ret < 0) { 84 dev_err(dev, "Failed to set pixel format: %d\n", ret); 85 return ret; 86 } 87 88 mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 89 0x00, 0x00, 0x08, 0x6f); 90 91 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 92 if (ret < 0) { 93 dev_err(dev, "Failed to exit sleep mode: %d\n", ret); 94 return ret; 95 } 96 msleep(70); 97 98 mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_MEMORY_START); 99 100 ret = mipi_dsi_dcs_set_display_on(dsi); 101 if (ret < 0) { 102 dev_err(dev, "Failed to turn display on: %d\n", ret); 103 return ret; 104 } 105 106 return 0; 107 } 108 109 static int sony_td4353_jdi_off(struct sony_td4353_jdi *ctx) 110 { 111 struct mipi_dsi_device *dsi = ctx->dsi; 112 struct device *dev = &dsi->dev; 113 int ret; 114 115 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 116 117 ret = mipi_dsi_dcs_set_display_off(dsi); 118 if (ret < 0) { 119 dev_err(dev, "Failed to set display off: %d\n", ret); 120 return ret; 121 } 122 msleep(22); 123 124 ret = mipi_dsi_dcs_set_tear_off(dsi); 125 if (ret < 0) { 126 dev_err(dev, "Failed to set tear off: %d\n", ret); 127 return ret; 128 } 129 130 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 131 if (ret < 0) { 132 dev_err(dev, "Failed to enter sleep mode: %d\n", ret); 133 return ret; 134 } 135 msleep(80); 136 137 return 0; 138 } 139 140 static void sony_td4353_assert_reset_gpios(struct sony_td4353_jdi *ctx, int mode) 141 { 142 gpiod_set_value_cansleep(ctx->touch_reset_gpio, mode); 143 gpiod_set_value_cansleep(ctx->panel_reset_gpio, mode); 144 usleep_range(5000, 5100); 145 } 146 147 static int sony_td4353_jdi_prepare(struct drm_panel *panel) 148 { 149 struct sony_td4353_jdi *ctx = to_sony_td4353_jdi(panel); 150 struct device *dev = &ctx->dsi->dev; 151 int ret; 152 153 if (ctx->prepared) 154 return 0; 155 156 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 157 if (ret < 0) { 158 dev_err(dev, "Failed to enable regulators: %d\n", ret); 159 return ret; 160 } 161 162 msleep(100); 163 164 sony_td4353_assert_reset_gpios(ctx, 1); 165 166 ret = sony_td4353_jdi_on(ctx); 167 if (ret < 0) { 168 dev_err(dev, "Failed to power on panel: %d\n", ret); 169 sony_td4353_assert_reset_gpios(ctx, 0); 170 regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 171 return ret; 172 } 173 174 ctx->prepared = true; 175 return 0; 176 } 177 178 static int sony_td4353_jdi_unprepare(struct drm_panel *panel) 179 { 180 struct sony_td4353_jdi *ctx = to_sony_td4353_jdi(panel); 181 struct device *dev = &ctx->dsi->dev; 182 int ret; 183 184 if (!ctx->prepared) 185 return 0; 186 187 ret = sony_td4353_jdi_off(ctx); 188 if (ret < 0) 189 dev_err(dev, "Failed to power off panel: %d\n", ret); 190 191 sony_td4353_assert_reset_gpios(ctx, 0); 192 regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 193 194 ctx->prepared = false; 195 return 0; 196 } 197 198 static const struct drm_display_mode sony_td4353_jdi_mode_tama_60hz = { 199 .clock = (1080 + 4 + 8 + 8) * (2160 + 259 + 8 + 8) * 60 / 1000, 200 .hdisplay = 1080, 201 .hsync_start = 1080 + 4, 202 .hsync_end = 1080 + 4 + 8, 203 .htotal = 1080 + 4 + 8 + 8, 204 .vdisplay = 2160, 205 .vsync_start = 2160 + 259, 206 .vsync_end = 2160 + 259 + 8, 207 .vtotal = 2160 + 259 + 8 + 8, 208 .width_mm = 64, 209 .height_mm = 128, 210 }; 211 212 static int sony_td4353_jdi_get_modes(struct drm_panel *panel, 213 struct drm_connector *connector) 214 { 215 struct sony_td4353_jdi *ctx = to_sony_td4353_jdi(panel); 216 struct drm_display_mode *mode = NULL; 217 218 if (ctx->type == TYPE_TAMA_60HZ) 219 mode = drm_mode_duplicate(connector->dev, &sony_td4353_jdi_mode_tama_60hz); 220 else 221 return -EINVAL; 222 223 if (!mode) 224 return -ENOMEM; 225 226 drm_mode_set_name(mode); 227 228 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 229 connector->display_info.width_mm = mode->width_mm; 230 connector->display_info.height_mm = mode->height_mm; 231 drm_mode_probed_add(connector, mode); 232 233 return 1; 234 } 235 236 static const struct drm_panel_funcs sony_td4353_jdi_panel_funcs = { 237 .prepare = sony_td4353_jdi_prepare, 238 .unprepare = sony_td4353_jdi_unprepare, 239 .get_modes = sony_td4353_jdi_get_modes, 240 }; 241 242 static int sony_td4353_jdi_probe(struct mipi_dsi_device *dsi) 243 { 244 struct device *dev = &dsi->dev; 245 struct sony_td4353_jdi *ctx; 246 int ret; 247 248 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 249 if (!ctx) 250 return -ENOMEM; 251 252 ctx->type = (uintptr_t)of_device_get_match_data(dev); 253 254 ctx->supplies[0].supply = "vddio"; 255 ctx->supplies[1].supply = "vsp"; 256 ctx->supplies[2].supply = "vsn"; 257 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), 258 ctx->supplies); 259 if (ret < 0) 260 return dev_err_probe(dev, ret, "Failed to get regulators\n"); 261 262 ctx->panel_reset_gpio = devm_gpiod_get(dev, "panel-reset", GPIOD_ASIS); 263 if (IS_ERR(ctx->panel_reset_gpio)) 264 return dev_err_probe(dev, PTR_ERR(ctx->panel_reset_gpio), 265 "Failed to get panel-reset-gpios\n"); 266 267 ctx->touch_reset_gpio = devm_gpiod_get(dev, "touch-reset", GPIOD_ASIS); 268 if (IS_ERR(ctx->touch_reset_gpio)) 269 return dev_err_probe(dev, PTR_ERR(ctx->touch_reset_gpio), 270 "Failed to get touch-reset-gpios\n"); 271 272 ctx->dsi = dsi; 273 mipi_dsi_set_drvdata(dsi, ctx); 274 275 dsi->lanes = 4; 276 dsi->format = MIPI_DSI_FMT_RGB888; 277 dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS; 278 279 drm_panel_init(&ctx->panel, dev, &sony_td4353_jdi_panel_funcs, 280 DRM_MODE_CONNECTOR_DSI); 281 282 ret = drm_panel_of_backlight(&ctx->panel); 283 if (ret) 284 return dev_err_probe(dev, ret, "Failed to get backlight\n"); 285 286 drm_panel_add(&ctx->panel); 287 288 ret = mipi_dsi_attach(dsi); 289 if (ret < 0) { 290 dev_err(dev, "Failed to attach to DSI host: %d\n", ret); 291 drm_panel_remove(&ctx->panel); 292 return ret; 293 } 294 295 return 0; 296 } 297 298 static void sony_td4353_jdi_remove(struct mipi_dsi_device *dsi) 299 { 300 struct sony_td4353_jdi *ctx = mipi_dsi_get_drvdata(dsi); 301 int ret; 302 303 ret = mipi_dsi_detach(dsi); 304 if (ret < 0) 305 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 306 307 drm_panel_remove(&ctx->panel); 308 } 309 310 static const struct of_device_id sony_td4353_jdi_of_match[] = { 311 { .compatible = "sony,td4353-jdi-tama", .data = (void *)TYPE_TAMA_60HZ }, 312 { /* sentinel */ } 313 }; 314 MODULE_DEVICE_TABLE(of, sony_td4353_jdi_of_match); 315 316 static struct mipi_dsi_driver sony_td4353_jdi_driver = { 317 .probe = sony_td4353_jdi_probe, 318 .remove = sony_td4353_jdi_remove, 319 .driver = { 320 .name = "panel-sony-td4353-jdi", 321 .of_match_table = sony_td4353_jdi_of_match, 322 }, 323 }; 324 module_mipi_dsi_driver(sony_td4353_jdi_driver); 325 326 MODULE_AUTHOR("Konrad Dybcio <konrad.dybcio@somainline.org>"); 327 MODULE_DESCRIPTION("DRM panel driver for SONY Xperia XZ2/XZ2c JDI panel"); 328 MODULE_LICENSE("GPL"); 329