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