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