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