1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2015 Red Hat 4 * Copyright (C) 2015 Sony Mobile Communications Inc. 5 * Author: Werner Johansson <werner.johansson@sonymobile.com> 6 * 7 * Based on AUO panel driver by Rob Clark <robdclark@gmail.com> 8 */ 9 10 #include <linux/backlight.h> 11 #include <linux/delay.h> 12 #include <linux/gpio/consumer.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/regulator/consumer.h> 16 17 #include <video/mipi_display.h> 18 19 #include <drm/drm_crtc.h> 20 #include <drm/drm_device.h> 21 #include <drm/drm_mipi_dsi.h> 22 #include <drm/drm_panel.h> 23 24 struct sharp_nt_panel { 25 struct drm_panel base; 26 struct mipi_dsi_device *dsi; 27 28 struct backlight_device *backlight; 29 struct regulator *supply; 30 struct gpio_desc *reset_gpio; 31 32 bool prepared; 33 bool enabled; 34 35 const struct drm_display_mode *mode; 36 }; 37 38 static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel) 39 { 40 return container_of(panel, struct sharp_nt_panel, base); 41 } 42 43 static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt) 44 { 45 struct mipi_dsi_device *dsi = sharp_nt->dsi; 46 int ret; 47 48 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 49 50 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 51 if (ret < 0) 52 return ret; 53 54 msleep(120); 55 56 /* Novatek two-lane operation */ 57 ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1); 58 if (ret < 0) 59 return ret; 60 61 /* Set both MCU and RGB I/F to 24bpp */ 62 ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT | 63 (MIPI_DCS_PIXEL_FMT_24BIT << 4)); 64 if (ret < 0) 65 return ret; 66 67 return 0; 68 } 69 70 static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt) 71 { 72 struct mipi_dsi_device *dsi = sharp_nt->dsi; 73 int ret; 74 75 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 76 77 ret = mipi_dsi_dcs_set_display_on(dsi); 78 if (ret < 0) 79 return ret; 80 81 return 0; 82 } 83 84 static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt) 85 { 86 struct mipi_dsi_device *dsi = sharp_nt->dsi; 87 int ret; 88 89 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 90 91 ret = mipi_dsi_dcs_set_display_off(dsi); 92 if (ret < 0) 93 return ret; 94 95 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 96 if (ret < 0) 97 return ret; 98 99 return 0; 100 } 101 102 103 static int sharp_nt_panel_disable(struct drm_panel *panel) 104 { 105 struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); 106 107 if (!sharp_nt->enabled) 108 return 0; 109 110 backlight_disable(sharp_nt->backlight); 111 112 sharp_nt->enabled = false; 113 114 return 0; 115 } 116 117 static int sharp_nt_panel_unprepare(struct drm_panel *panel) 118 { 119 struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); 120 int ret; 121 122 if (!sharp_nt->prepared) 123 return 0; 124 125 ret = sharp_nt_panel_off(sharp_nt); 126 if (ret < 0) { 127 dev_err(panel->dev, "failed to set panel off: %d\n", ret); 128 return ret; 129 } 130 131 regulator_disable(sharp_nt->supply); 132 if (sharp_nt->reset_gpio) 133 gpiod_set_value(sharp_nt->reset_gpio, 0); 134 135 sharp_nt->prepared = false; 136 137 return 0; 138 } 139 140 static int sharp_nt_panel_prepare(struct drm_panel *panel) 141 { 142 struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); 143 int ret; 144 145 if (sharp_nt->prepared) 146 return 0; 147 148 ret = regulator_enable(sharp_nt->supply); 149 if (ret < 0) 150 return ret; 151 152 msleep(20); 153 154 if (sharp_nt->reset_gpio) { 155 gpiod_set_value(sharp_nt->reset_gpio, 1); 156 msleep(1); 157 gpiod_set_value(sharp_nt->reset_gpio, 0); 158 msleep(1); 159 gpiod_set_value(sharp_nt->reset_gpio, 1); 160 msleep(10); 161 } 162 163 ret = sharp_nt_panel_init(sharp_nt); 164 if (ret < 0) { 165 dev_err(panel->dev, "failed to init panel: %d\n", ret); 166 goto poweroff; 167 } 168 169 ret = sharp_nt_panel_on(sharp_nt); 170 if (ret < 0) { 171 dev_err(panel->dev, "failed to set panel on: %d\n", ret); 172 goto poweroff; 173 } 174 175 sharp_nt->prepared = true; 176 177 return 0; 178 179 poweroff: 180 regulator_disable(sharp_nt->supply); 181 if (sharp_nt->reset_gpio) 182 gpiod_set_value(sharp_nt->reset_gpio, 0); 183 return ret; 184 } 185 186 static int sharp_nt_panel_enable(struct drm_panel *panel) 187 { 188 struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel); 189 190 if (sharp_nt->enabled) 191 return 0; 192 193 backlight_enable(sharp_nt->backlight); 194 195 sharp_nt->enabled = true; 196 197 return 0; 198 } 199 200 static const struct drm_display_mode default_mode = { 201 .clock = 41118, 202 .hdisplay = 540, 203 .hsync_start = 540 + 48, 204 .hsync_end = 540 + 48 + 80, 205 .htotal = 540 + 48 + 80 + 32, 206 .vdisplay = 960, 207 .vsync_start = 960 + 3, 208 .vsync_end = 960 + 3 + 15, 209 .vtotal = 960 + 3 + 15 + 1, 210 .vrefresh = 60, 211 }; 212 213 static int sharp_nt_panel_get_modes(struct drm_panel *panel) 214 { 215 struct drm_display_mode *mode; 216 217 mode = drm_mode_duplicate(panel->drm, &default_mode); 218 if (!mode) { 219 dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", 220 default_mode.hdisplay, default_mode.vdisplay, 221 default_mode.vrefresh); 222 return -ENOMEM; 223 } 224 225 drm_mode_set_name(mode); 226 227 drm_mode_probed_add(panel->connector, mode); 228 229 panel->connector->display_info.width_mm = 54; 230 panel->connector->display_info.height_mm = 95; 231 232 return 1; 233 } 234 235 static const struct drm_panel_funcs sharp_nt_panel_funcs = { 236 .disable = sharp_nt_panel_disable, 237 .unprepare = sharp_nt_panel_unprepare, 238 .prepare = sharp_nt_panel_prepare, 239 .enable = sharp_nt_panel_enable, 240 .get_modes = sharp_nt_panel_get_modes, 241 }; 242 243 static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt) 244 { 245 struct device *dev = &sharp_nt->dsi->dev; 246 247 sharp_nt->mode = &default_mode; 248 249 sharp_nt->supply = devm_regulator_get(dev, "avdd"); 250 if (IS_ERR(sharp_nt->supply)) 251 return PTR_ERR(sharp_nt->supply); 252 253 sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 254 if (IS_ERR(sharp_nt->reset_gpio)) { 255 dev_err(dev, "cannot get reset-gpios %ld\n", 256 PTR_ERR(sharp_nt->reset_gpio)); 257 sharp_nt->reset_gpio = NULL; 258 } else { 259 gpiod_set_value(sharp_nt->reset_gpio, 0); 260 } 261 262 sharp_nt->backlight = devm_of_find_backlight(dev); 263 264 if (IS_ERR(sharp_nt->backlight)) 265 return PTR_ERR(sharp_nt->backlight); 266 267 drm_panel_init(&sharp_nt->base); 268 sharp_nt->base.funcs = &sharp_nt_panel_funcs; 269 sharp_nt->base.dev = &sharp_nt->dsi->dev; 270 271 return drm_panel_add(&sharp_nt->base); 272 } 273 274 static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt) 275 { 276 if (sharp_nt->base.dev) 277 drm_panel_remove(&sharp_nt->base); 278 } 279 280 static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi) 281 { 282 struct sharp_nt_panel *sharp_nt; 283 int ret; 284 285 dsi->lanes = 2; 286 dsi->format = MIPI_DSI_FMT_RGB888; 287 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | 288 MIPI_DSI_MODE_VIDEO_HSE | 289 MIPI_DSI_CLOCK_NON_CONTINUOUS | 290 MIPI_DSI_MODE_EOT_PACKET; 291 292 sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL); 293 if (!sharp_nt) 294 return -ENOMEM; 295 296 mipi_dsi_set_drvdata(dsi, sharp_nt); 297 298 sharp_nt->dsi = dsi; 299 300 ret = sharp_nt_panel_add(sharp_nt); 301 if (ret < 0) 302 return ret; 303 304 return mipi_dsi_attach(dsi); 305 } 306 307 static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi) 308 { 309 struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi); 310 int ret; 311 312 ret = sharp_nt_panel_disable(&sharp_nt->base); 313 if (ret < 0) 314 dev_err(&dsi->dev, "failed to disable panel: %d\n", ret); 315 316 ret = mipi_dsi_detach(dsi); 317 if (ret < 0) 318 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); 319 320 sharp_nt_panel_del(sharp_nt); 321 322 return 0; 323 } 324 325 static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi) 326 { 327 struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi); 328 329 sharp_nt_panel_disable(&sharp_nt->base); 330 } 331 332 static const struct of_device_id sharp_nt_of_match[] = { 333 { .compatible = "sharp,ls043t1le01-qhd", }, 334 { } 335 }; 336 MODULE_DEVICE_TABLE(of, sharp_nt_of_match); 337 338 static struct mipi_dsi_driver sharp_nt_panel_driver = { 339 .driver = { 340 .name = "panel-sharp-ls043t1le01-qhd", 341 .of_match_table = sharp_nt_of_match, 342 }, 343 .probe = sharp_nt_panel_probe, 344 .remove = sharp_nt_panel_remove, 345 .shutdown = sharp_nt_panel_shutdown, 346 }; 347 module_mipi_dsi_driver(sharp_nt_panel_driver); 348 349 MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>"); 350 MODULE_DESCRIPTION("Sharp LS043T1LE01 NT35565-based qHD (540x960) video mode panel driver"); 351 MODULE_LICENSE("GPL v2"); 352