1 /* 2 * LCD panel driver for Sharp LS037V7DW01 3 * 4 * Copyright (C) 2013 Texas Instruments 5 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation. 10 */ 11 12 #include <linux/delay.h> 13 #include <linux/gpio.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/of_gpio.h> 17 #include <linux/platform_device.h> 18 #include <linux/slab.h> 19 #include <linux/regulator/consumer.h> 20 #include <video/omapfb_dss.h> 21 22 struct panel_drv_data { 23 struct omap_dss_device dssdev; 24 struct omap_dss_device *in; 25 struct regulator *vcc; 26 27 int data_lines; 28 29 struct omap_video_timings videomode; 30 31 struct gpio_desc *resb_gpio; /* low = reset active min 20 us */ 32 struct gpio_desc *ini_gpio; /* high = power on */ 33 struct gpio_desc *mo_gpio; /* low = 480x640, high = 240x320 */ 34 struct gpio_desc *lr_gpio; /* high = conventional horizontal scanning */ 35 struct gpio_desc *ud_gpio; /* high = conventional vertical scanning */ 36 }; 37 38 static const struct omap_video_timings sharp_ls_timings = { 39 .x_res = 480, 40 .y_res = 640, 41 42 .pixelclock = 19200000, 43 44 .hsw = 2, 45 .hfp = 1, 46 .hbp = 28, 47 48 .vsw = 1, 49 .vfp = 1, 50 .vbp = 1, 51 52 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, 53 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, 54 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, 55 .de_level = OMAPDSS_SIG_ACTIVE_HIGH, 56 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, 57 }; 58 59 #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) 60 61 static int sharp_ls_connect(struct omap_dss_device *dssdev) 62 { 63 struct panel_drv_data *ddata = to_panel_data(dssdev); 64 struct omap_dss_device *in = ddata->in; 65 int r; 66 67 if (omapdss_device_is_connected(dssdev)) 68 return 0; 69 70 r = in->ops.dpi->connect(in, dssdev); 71 if (r) 72 return r; 73 74 return 0; 75 } 76 77 static void sharp_ls_disconnect(struct omap_dss_device *dssdev) 78 { 79 struct panel_drv_data *ddata = to_panel_data(dssdev); 80 struct omap_dss_device *in = ddata->in; 81 82 if (!omapdss_device_is_connected(dssdev)) 83 return; 84 85 in->ops.dpi->disconnect(in, dssdev); 86 } 87 88 static int sharp_ls_enable(struct omap_dss_device *dssdev) 89 { 90 struct panel_drv_data *ddata = to_panel_data(dssdev); 91 struct omap_dss_device *in = ddata->in; 92 int r; 93 94 if (!omapdss_device_is_connected(dssdev)) 95 return -ENODEV; 96 97 if (omapdss_device_is_enabled(dssdev)) 98 return 0; 99 100 if (ddata->data_lines) 101 in->ops.dpi->set_data_lines(in, ddata->data_lines); 102 in->ops.dpi->set_timings(in, &ddata->videomode); 103 104 if (ddata->vcc) { 105 r = regulator_enable(ddata->vcc); 106 if (r != 0) 107 return r; 108 } 109 110 r = in->ops.dpi->enable(in); 111 if (r) { 112 regulator_disable(ddata->vcc); 113 return r; 114 } 115 116 /* wait couple of vsyncs until enabling the LCD */ 117 msleep(50); 118 119 if (ddata->resb_gpio) 120 gpiod_set_value_cansleep(ddata->resb_gpio, 1); 121 122 if (ddata->ini_gpio) 123 gpiod_set_value_cansleep(ddata->ini_gpio, 1); 124 125 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 126 127 return 0; 128 } 129 130 static void sharp_ls_disable(struct omap_dss_device *dssdev) 131 { 132 struct panel_drv_data *ddata = to_panel_data(dssdev); 133 struct omap_dss_device *in = ddata->in; 134 135 if (!omapdss_device_is_enabled(dssdev)) 136 return; 137 138 if (ddata->ini_gpio) 139 gpiod_set_value_cansleep(ddata->ini_gpio, 0); 140 141 if (ddata->resb_gpio) 142 gpiod_set_value_cansleep(ddata->resb_gpio, 0); 143 144 /* wait at least 5 vsyncs after disabling the LCD */ 145 146 msleep(100); 147 148 in->ops.dpi->disable(in); 149 150 if (ddata->vcc) 151 regulator_disable(ddata->vcc); 152 153 dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 154 } 155 156 static void sharp_ls_set_timings(struct omap_dss_device *dssdev, 157 struct omap_video_timings *timings) 158 { 159 struct panel_drv_data *ddata = to_panel_data(dssdev); 160 struct omap_dss_device *in = ddata->in; 161 162 ddata->videomode = *timings; 163 dssdev->panel.timings = *timings; 164 165 in->ops.dpi->set_timings(in, timings); 166 } 167 168 static void sharp_ls_get_timings(struct omap_dss_device *dssdev, 169 struct omap_video_timings *timings) 170 { 171 struct panel_drv_data *ddata = to_panel_data(dssdev); 172 173 *timings = ddata->videomode; 174 } 175 176 static int sharp_ls_check_timings(struct omap_dss_device *dssdev, 177 struct omap_video_timings *timings) 178 { 179 struct panel_drv_data *ddata = to_panel_data(dssdev); 180 struct omap_dss_device *in = ddata->in; 181 182 return in->ops.dpi->check_timings(in, timings); 183 } 184 185 static struct omap_dss_driver sharp_ls_ops = { 186 .connect = sharp_ls_connect, 187 .disconnect = sharp_ls_disconnect, 188 189 .enable = sharp_ls_enable, 190 .disable = sharp_ls_disable, 191 192 .set_timings = sharp_ls_set_timings, 193 .get_timings = sharp_ls_get_timings, 194 .check_timings = sharp_ls_check_timings, 195 196 .get_resolution = omapdss_default_get_resolution, 197 }; 198 199 static int sharp_ls_get_gpio_of(struct device *dev, int index, int val, 200 const char *desc, struct gpio_desc **gpiod) 201 { 202 struct gpio_desc *gd; 203 204 *gpiod = NULL; 205 206 gd = devm_gpiod_get_index(dev, desc, index, GPIOD_OUT_LOW); 207 if (IS_ERR(gd)) 208 return PTR_ERR(gd); 209 210 *gpiod = gd; 211 return 0; 212 } 213 214 static int sharp_ls_probe_of(struct platform_device *pdev) 215 { 216 struct panel_drv_data *ddata = platform_get_drvdata(pdev); 217 struct device_node *node = pdev->dev.of_node; 218 struct omap_dss_device *in; 219 int r; 220 221 ddata->vcc = devm_regulator_get(&pdev->dev, "envdd"); 222 if (IS_ERR(ddata->vcc)) { 223 dev_err(&pdev->dev, "failed to get regulator\n"); 224 return PTR_ERR(ddata->vcc); 225 } 226 227 /* lcd INI */ 228 r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "enable", &ddata->ini_gpio); 229 if (r) 230 return r; 231 232 /* lcd RESB */ 233 r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "reset", &ddata->resb_gpio); 234 if (r) 235 return r; 236 237 /* lcd MO */ 238 r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "mode", &ddata->mo_gpio); 239 if (r) 240 return r; 241 242 /* lcd LR */ 243 r = sharp_ls_get_gpio_of(&pdev->dev, 1, 1, "mode", &ddata->lr_gpio); 244 if (r) 245 return r; 246 247 /* lcd UD */ 248 r = sharp_ls_get_gpio_of(&pdev->dev, 2, 1, "mode", &ddata->ud_gpio); 249 if (r) 250 return r; 251 252 in = omapdss_of_find_source_for_first_ep(node); 253 if (IS_ERR(in)) { 254 dev_err(&pdev->dev, "failed to find video source\n"); 255 return PTR_ERR(in); 256 } 257 258 ddata->in = in; 259 260 return 0; 261 } 262 263 static int sharp_ls_probe(struct platform_device *pdev) 264 { 265 struct panel_drv_data *ddata; 266 struct omap_dss_device *dssdev; 267 int r; 268 269 if (!pdev->dev.of_node) 270 return -ENODEV; 271 272 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); 273 if (ddata == NULL) 274 return -ENOMEM; 275 276 platform_set_drvdata(pdev, ddata); 277 278 r = sharp_ls_probe_of(pdev); 279 if (r) 280 return r; 281 282 ddata->videomode = sharp_ls_timings; 283 284 dssdev = &ddata->dssdev; 285 dssdev->dev = &pdev->dev; 286 dssdev->driver = &sharp_ls_ops; 287 dssdev->type = OMAP_DISPLAY_TYPE_DPI; 288 dssdev->owner = THIS_MODULE; 289 dssdev->panel.timings = ddata->videomode; 290 dssdev->phy.dpi.data_lines = ddata->data_lines; 291 292 r = omapdss_register_display(dssdev); 293 if (r) { 294 dev_err(&pdev->dev, "Failed to register panel\n"); 295 goto err_reg; 296 } 297 298 return 0; 299 300 err_reg: 301 omap_dss_put_device(ddata->in); 302 return r; 303 } 304 305 static int __exit sharp_ls_remove(struct platform_device *pdev) 306 { 307 struct panel_drv_data *ddata = platform_get_drvdata(pdev); 308 struct omap_dss_device *dssdev = &ddata->dssdev; 309 struct omap_dss_device *in = ddata->in; 310 311 omapdss_unregister_display(dssdev); 312 313 sharp_ls_disable(dssdev); 314 sharp_ls_disconnect(dssdev); 315 316 omap_dss_put_device(in); 317 318 return 0; 319 } 320 321 static const struct of_device_id sharp_ls_of_match[] = { 322 { .compatible = "omapdss,sharp,ls037v7dw01", }, 323 {}, 324 }; 325 326 MODULE_DEVICE_TABLE(of, sharp_ls_of_match); 327 328 static struct platform_driver sharp_ls_driver = { 329 .probe = sharp_ls_probe, 330 .remove = __exit_p(sharp_ls_remove), 331 .driver = { 332 .name = "panel-sharp-ls037v7dw01", 333 .of_match_table = sharp_ls_of_match, 334 .suppress_bind_attrs = true, 335 }, 336 }; 337 338 module_platform_driver(sharp_ls_driver); 339 340 MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); 341 MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver"); 342 MODULE_LICENSE("GPL"); 343