1f76ee892STomi Valkeinen /* 2f76ee892STomi Valkeinen * LG.Philips LB035Q02 LCD Panel driver 3f76ee892STomi Valkeinen * 4f76ee892STomi Valkeinen * Copyright (C) 2013 Texas Instruments 5f76ee892STomi Valkeinen * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> 6f76ee892STomi Valkeinen * Based on a driver by: Steve Sakoman <steve@sakoman.com> 7f76ee892STomi Valkeinen * 8f76ee892STomi Valkeinen * This program is free software; you can redistribute it and/or modify it 9f76ee892STomi Valkeinen * under the terms of the GNU General Public License version 2 as published by 10f76ee892STomi Valkeinen * the Free Software Foundation. 11f76ee892STomi Valkeinen */ 12f76ee892STomi Valkeinen 13f76ee892STomi Valkeinen #include <linux/module.h> 14f76ee892STomi Valkeinen #include <linux/delay.h> 15f76ee892STomi Valkeinen #include <linux/spi/spi.h> 16f76ee892STomi Valkeinen #include <linux/mutex.h> 17f76ee892STomi Valkeinen #include <linux/gpio.h> 18f76ee892STomi Valkeinen 19f76ee892STomi Valkeinen #include <video/omapdss.h> 20f76ee892STomi Valkeinen #include <video/omap-panel-data.h> 21f76ee892STomi Valkeinen 22f76ee892STomi Valkeinen static struct omap_video_timings lb035q02_timings = { 23f76ee892STomi Valkeinen .x_res = 320, 24f76ee892STomi Valkeinen .y_res = 240, 25f76ee892STomi Valkeinen 26f76ee892STomi Valkeinen .pixelclock = 6500000, 27f76ee892STomi Valkeinen 28f76ee892STomi Valkeinen .hsw = 2, 29f76ee892STomi Valkeinen .hfp = 20, 30f76ee892STomi Valkeinen .hbp = 68, 31f76ee892STomi Valkeinen 32f76ee892STomi Valkeinen .vsw = 2, 33f76ee892STomi Valkeinen .vfp = 4, 34f76ee892STomi Valkeinen .vbp = 18, 35f76ee892STomi Valkeinen 36f76ee892STomi Valkeinen .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, 37f76ee892STomi Valkeinen .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, 38f76ee892STomi Valkeinen .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, 39f76ee892STomi Valkeinen .de_level = OMAPDSS_SIG_ACTIVE_HIGH, 40f76ee892STomi Valkeinen .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, 41f76ee892STomi Valkeinen }; 42f76ee892STomi Valkeinen 43f76ee892STomi Valkeinen struct panel_drv_data { 44f76ee892STomi Valkeinen struct omap_dss_device dssdev; 45f76ee892STomi Valkeinen struct omap_dss_device *in; 46f76ee892STomi Valkeinen 47f76ee892STomi Valkeinen struct spi_device *spi; 48f76ee892STomi Valkeinen 49f76ee892STomi Valkeinen int data_lines; 50f76ee892STomi Valkeinen 51f76ee892STomi Valkeinen struct omap_video_timings videomode; 52f76ee892STomi Valkeinen 53f76ee892STomi Valkeinen /* used for non-DT boot, to be removed */ 54f76ee892STomi Valkeinen int backlight_gpio; 55f76ee892STomi Valkeinen 56f76ee892STomi Valkeinen struct gpio_desc *enable_gpio; 57f76ee892STomi Valkeinen }; 58f76ee892STomi Valkeinen 59f76ee892STomi Valkeinen #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) 60f76ee892STomi Valkeinen 61f76ee892STomi Valkeinen static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val) 62f76ee892STomi Valkeinen { 63f76ee892STomi Valkeinen struct spi_message msg; 64f76ee892STomi Valkeinen struct spi_transfer index_xfer = { 65f76ee892STomi Valkeinen .len = 3, 66f76ee892STomi Valkeinen .cs_change = 1, 67f76ee892STomi Valkeinen }; 68f76ee892STomi Valkeinen struct spi_transfer value_xfer = { 69f76ee892STomi Valkeinen .len = 3, 70f76ee892STomi Valkeinen }; 71f76ee892STomi Valkeinen u8 buffer[16]; 72f76ee892STomi Valkeinen 73f76ee892STomi Valkeinen spi_message_init(&msg); 74f76ee892STomi Valkeinen 75f76ee892STomi Valkeinen /* register index */ 76f76ee892STomi Valkeinen buffer[0] = 0x70; 77f76ee892STomi Valkeinen buffer[1] = 0x00; 78f76ee892STomi Valkeinen buffer[2] = reg & 0x7f; 79f76ee892STomi Valkeinen index_xfer.tx_buf = buffer; 80f76ee892STomi Valkeinen spi_message_add_tail(&index_xfer, &msg); 81f76ee892STomi Valkeinen 82f76ee892STomi Valkeinen /* register value */ 83f76ee892STomi Valkeinen buffer[4] = 0x72; 84f76ee892STomi Valkeinen buffer[5] = val >> 8; 85f76ee892STomi Valkeinen buffer[6] = val; 86f76ee892STomi Valkeinen value_xfer.tx_buf = buffer + 4; 87f76ee892STomi Valkeinen spi_message_add_tail(&value_xfer, &msg); 88f76ee892STomi Valkeinen 89f76ee892STomi Valkeinen return spi_sync(spi, &msg); 90f76ee892STomi Valkeinen } 91f76ee892STomi Valkeinen 92f76ee892STomi Valkeinen static void init_lb035q02_panel(struct spi_device *spi) 93f76ee892STomi Valkeinen { 94f76ee892STomi Valkeinen /* Init sequence from page 28 of the lb035q02 spec */ 95f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x01, 0x6300); 96f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x02, 0x0200); 97f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x03, 0x0177); 98f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x04, 0x04c7); 99f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x05, 0xffc0); 100f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x06, 0xe806); 101f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x0a, 0x4008); 102f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x0b, 0x0000); 103f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x0d, 0x0030); 104f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x0e, 0x2800); 105f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x0f, 0x0000); 106f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x16, 0x9f80); 107f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x17, 0x0a0f); 108f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x1e, 0x00c1); 109f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x30, 0x0300); 110f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x31, 0x0007); 111f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x32, 0x0000); 112f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x33, 0x0000); 113f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x34, 0x0707); 114f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x35, 0x0004); 115f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x36, 0x0302); 116f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x37, 0x0202); 117f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x3a, 0x0a0d); 118f76ee892STomi Valkeinen lb035q02_write_reg(spi, 0x3b, 0x0806); 119f76ee892STomi Valkeinen } 120f76ee892STomi Valkeinen 121f76ee892STomi Valkeinen static int lb035q02_connect(struct omap_dss_device *dssdev) 122f76ee892STomi Valkeinen { 123f76ee892STomi Valkeinen struct panel_drv_data *ddata = to_panel_data(dssdev); 124f76ee892STomi Valkeinen struct omap_dss_device *in = ddata->in; 125f76ee892STomi Valkeinen int r; 126f76ee892STomi Valkeinen 127f76ee892STomi Valkeinen if (omapdss_device_is_connected(dssdev)) 128f76ee892STomi Valkeinen return 0; 129f76ee892STomi Valkeinen 130f76ee892STomi Valkeinen r = in->ops.dpi->connect(in, dssdev); 131f76ee892STomi Valkeinen if (r) 132f76ee892STomi Valkeinen return r; 133f76ee892STomi Valkeinen 134f76ee892STomi Valkeinen init_lb035q02_panel(ddata->spi); 135f76ee892STomi Valkeinen 136f76ee892STomi Valkeinen return 0; 137f76ee892STomi Valkeinen } 138f76ee892STomi Valkeinen 139f76ee892STomi Valkeinen static void lb035q02_disconnect(struct omap_dss_device *dssdev) 140f76ee892STomi Valkeinen { 141f76ee892STomi Valkeinen struct panel_drv_data *ddata = to_panel_data(dssdev); 142f76ee892STomi Valkeinen struct omap_dss_device *in = ddata->in; 143f76ee892STomi Valkeinen 144f76ee892STomi Valkeinen if (!omapdss_device_is_connected(dssdev)) 145f76ee892STomi Valkeinen return; 146f76ee892STomi Valkeinen 147f76ee892STomi Valkeinen in->ops.dpi->disconnect(in, dssdev); 148f76ee892STomi Valkeinen } 149f76ee892STomi Valkeinen 150f76ee892STomi Valkeinen static int lb035q02_enable(struct omap_dss_device *dssdev) 151f76ee892STomi Valkeinen { 152f76ee892STomi Valkeinen struct panel_drv_data *ddata = to_panel_data(dssdev); 153f76ee892STomi Valkeinen struct omap_dss_device *in = ddata->in; 154f76ee892STomi Valkeinen int r; 155f76ee892STomi Valkeinen 156f76ee892STomi Valkeinen if (!omapdss_device_is_connected(dssdev)) 157f76ee892STomi Valkeinen return -ENODEV; 158f76ee892STomi Valkeinen 159f76ee892STomi Valkeinen if (omapdss_device_is_enabled(dssdev)) 160f76ee892STomi Valkeinen return 0; 161f76ee892STomi Valkeinen 162f76ee892STomi Valkeinen if (ddata->data_lines) 163f76ee892STomi Valkeinen in->ops.dpi->set_data_lines(in, ddata->data_lines); 164f76ee892STomi Valkeinen in->ops.dpi->set_timings(in, &ddata->videomode); 165f76ee892STomi Valkeinen 166f76ee892STomi Valkeinen r = in->ops.dpi->enable(in); 167f76ee892STomi Valkeinen if (r) 168f76ee892STomi Valkeinen return r; 169f76ee892STomi Valkeinen 170f76ee892STomi Valkeinen if (ddata->enable_gpio) 171f76ee892STomi Valkeinen gpiod_set_value_cansleep(ddata->enable_gpio, 1); 172f76ee892STomi Valkeinen 173f76ee892STomi Valkeinen if (gpio_is_valid(ddata->backlight_gpio)) 174f76ee892STomi Valkeinen gpio_set_value_cansleep(ddata->backlight_gpio, 1); 175f76ee892STomi Valkeinen 176f76ee892STomi Valkeinen dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 177f76ee892STomi Valkeinen 178f76ee892STomi Valkeinen return 0; 179f76ee892STomi Valkeinen } 180f76ee892STomi Valkeinen 181f76ee892STomi Valkeinen static void lb035q02_disable(struct omap_dss_device *dssdev) 182f76ee892STomi Valkeinen { 183f76ee892STomi Valkeinen struct panel_drv_data *ddata = to_panel_data(dssdev); 184f76ee892STomi Valkeinen struct omap_dss_device *in = ddata->in; 185f76ee892STomi Valkeinen 186f76ee892STomi Valkeinen if (!omapdss_device_is_enabled(dssdev)) 187f76ee892STomi Valkeinen return; 188f76ee892STomi Valkeinen 189f76ee892STomi Valkeinen if (ddata->enable_gpio) 190f76ee892STomi Valkeinen gpiod_set_value_cansleep(ddata->enable_gpio, 0); 191f76ee892STomi Valkeinen 192f76ee892STomi Valkeinen if (gpio_is_valid(ddata->backlight_gpio)) 193f76ee892STomi Valkeinen gpio_set_value_cansleep(ddata->backlight_gpio, 0); 194f76ee892STomi Valkeinen 195f76ee892STomi Valkeinen in->ops.dpi->disable(in); 196f76ee892STomi Valkeinen 197f76ee892STomi Valkeinen dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 198f76ee892STomi Valkeinen } 199f76ee892STomi Valkeinen 200f76ee892STomi Valkeinen static void lb035q02_set_timings(struct omap_dss_device *dssdev, 201f76ee892STomi Valkeinen struct omap_video_timings *timings) 202f76ee892STomi Valkeinen { 203f76ee892STomi Valkeinen struct panel_drv_data *ddata = to_panel_data(dssdev); 204f76ee892STomi Valkeinen struct omap_dss_device *in = ddata->in; 205f76ee892STomi Valkeinen 206f76ee892STomi Valkeinen ddata->videomode = *timings; 207f76ee892STomi Valkeinen dssdev->panel.timings = *timings; 208f76ee892STomi Valkeinen 209f76ee892STomi Valkeinen in->ops.dpi->set_timings(in, timings); 210f76ee892STomi Valkeinen } 211f76ee892STomi Valkeinen 212f76ee892STomi Valkeinen static void lb035q02_get_timings(struct omap_dss_device *dssdev, 213f76ee892STomi Valkeinen struct omap_video_timings *timings) 214f76ee892STomi Valkeinen { 215f76ee892STomi Valkeinen struct panel_drv_data *ddata = to_panel_data(dssdev); 216f76ee892STomi Valkeinen 217f76ee892STomi Valkeinen *timings = ddata->videomode; 218f76ee892STomi Valkeinen } 219f76ee892STomi Valkeinen 220f76ee892STomi Valkeinen static int lb035q02_check_timings(struct omap_dss_device *dssdev, 221f76ee892STomi Valkeinen struct omap_video_timings *timings) 222f76ee892STomi Valkeinen { 223f76ee892STomi Valkeinen struct panel_drv_data *ddata = to_panel_data(dssdev); 224f76ee892STomi Valkeinen struct omap_dss_device *in = ddata->in; 225f76ee892STomi Valkeinen 226f76ee892STomi Valkeinen return in->ops.dpi->check_timings(in, timings); 227f76ee892STomi Valkeinen } 228f76ee892STomi Valkeinen 229f76ee892STomi Valkeinen static struct omap_dss_driver lb035q02_ops = { 230f76ee892STomi Valkeinen .connect = lb035q02_connect, 231f76ee892STomi Valkeinen .disconnect = lb035q02_disconnect, 232f76ee892STomi Valkeinen 233f76ee892STomi Valkeinen .enable = lb035q02_enable, 234f76ee892STomi Valkeinen .disable = lb035q02_disable, 235f76ee892STomi Valkeinen 236f76ee892STomi Valkeinen .set_timings = lb035q02_set_timings, 237f76ee892STomi Valkeinen .get_timings = lb035q02_get_timings, 238f76ee892STomi Valkeinen .check_timings = lb035q02_check_timings, 239f76ee892STomi Valkeinen 240f76ee892STomi Valkeinen .get_resolution = omapdss_default_get_resolution, 241f76ee892STomi Valkeinen }; 242f76ee892STomi Valkeinen 243f76ee892STomi Valkeinen static int lb035q02_probe_pdata(struct spi_device *spi) 244f76ee892STomi Valkeinen { 245f76ee892STomi Valkeinen const struct panel_lb035q02_platform_data *pdata; 246f76ee892STomi Valkeinen struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); 247f76ee892STomi Valkeinen struct omap_dss_device *dssdev, *in; 248f76ee892STomi Valkeinen int r; 249f76ee892STomi Valkeinen 250f76ee892STomi Valkeinen pdata = dev_get_platdata(&spi->dev); 251f76ee892STomi Valkeinen 252f76ee892STomi Valkeinen in = omap_dss_find_output(pdata->source); 253f76ee892STomi Valkeinen if (in == NULL) { 254f76ee892STomi Valkeinen dev_err(&spi->dev, "failed to find video source '%s'\n", 255f76ee892STomi Valkeinen pdata->source); 256f76ee892STomi Valkeinen return -EPROBE_DEFER; 257f76ee892STomi Valkeinen } 258f76ee892STomi Valkeinen 259f76ee892STomi Valkeinen ddata->in = in; 260f76ee892STomi Valkeinen 261f76ee892STomi Valkeinen ddata->data_lines = pdata->data_lines; 262f76ee892STomi Valkeinen 263f76ee892STomi Valkeinen dssdev = &ddata->dssdev; 264f76ee892STomi Valkeinen dssdev->name = pdata->name; 265f76ee892STomi Valkeinen 266f76ee892STomi Valkeinen r = devm_gpio_request_one(&spi->dev, pdata->enable_gpio, 267f76ee892STomi Valkeinen GPIOF_OUT_INIT_LOW, "panel enable"); 268f76ee892STomi Valkeinen if (r) 269f76ee892STomi Valkeinen goto err_gpio; 270f76ee892STomi Valkeinen 271f76ee892STomi Valkeinen ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio); 272f76ee892STomi Valkeinen 273f76ee892STomi Valkeinen ddata->backlight_gpio = pdata->backlight_gpio; 274f76ee892STomi Valkeinen 275f76ee892STomi Valkeinen return 0; 276f76ee892STomi Valkeinen err_gpio: 277f76ee892STomi Valkeinen omap_dss_put_device(ddata->in); 278f76ee892STomi Valkeinen return r; 279f76ee892STomi Valkeinen } 280f76ee892STomi Valkeinen 281f76ee892STomi Valkeinen static int lb035q02_probe_of(struct spi_device *spi) 282f76ee892STomi Valkeinen { 283f76ee892STomi Valkeinen struct device_node *node = spi->dev.of_node; 284f76ee892STomi Valkeinen struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); 285f76ee892STomi Valkeinen struct omap_dss_device *in; 286f76ee892STomi Valkeinen struct gpio_desc *gpio; 287f76ee892STomi Valkeinen 288f76ee892STomi Valkeinen gpio = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW); 289f76ee892STomi Valkeinen if (IS_ERR(gpio)) { 290f76ee892STomi Valkeinen dev_err(&spi->dev, "failed to parse enable gpio\n"); 291f76ee892STomi Valkeinen return PTR_ERR(gpio); 292f76ee892STomi Valkeinen } 293f76ee892STomi Valkeinen 294f76ee892STomi Valkeinen ddata->enable_gpio = gpio; 295f76ee892STomi Valkeinen 296f76ee892STomi Valkeinen ddata->backlight_gpio = -ENOENT; 297f76ee892STomi Valkeinen 298f76ee892STomi Valkeinen in = omapdss_of_find_source_for_first_ep(node); 299f76ee892STomi Valkeinen if (IS_ERR(in)) { 300f76ee892STomi Valkeinen dev_err(&spi->dev, "failed to find video source\n"); 301f76ee892STomi Valkeinen return PTR_ERR(in); 302f76ee892STomi Valkeinen } 303f76ee892STomi Valkeinen 304f76ee892STomi Valkeinen ddata->in = in; 305f76ee892STomi Valkeinen 306f76ee892STomi Valkeinen return 0; 307f76ee892STomi Valkeinen } 308f76ee892STomi Valkeinen 309f76ee892STomi Valkeinen static int lb035q02_panel_spi_probe(struct spi_device *spi) 310f76ee892STomi Valkeinen { 311f76ee892STomi Valkeinen struct panel_drv_data *ddata; 312f76ee892STomi Valkeinen struct omap_dss_device *dssdev; 313f76ee892STomi Valkeinen int r; 314f76ee892STomi Valkeinen 315f76ee892STomi Valkeinen ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); 316f76ee892STomi Valkeinen if (ddata == NULL) 317f76ee892STomi Valkeinen return -ENOMEM; 318f76ee892STomi Valkeinen 319f76ee892STomi Valkeinen dev_set_drvdata(&spi->dev, ddata); 320f76ee892STomi Valkeinen 321f76ee892STomi Valkeinen ddata->spi = spi; 322f76ee892STomi Valkeinen 323f76ee892STomi Valkeinen if (dev_get_platdata(&spi->dev)) { 324f76ee892STomi Valkeinen r = lb035q02_probe_pdata(spi); 325f76ee892STomi Valkeinen if (r) 326f76ee892STomi Valkeinen return r; 327f76ee892STomi Valkeinen } else if (spi->dev.of_node) { 328f76ee892STomi Valkeinen r = lb035q02_probe_of(spi); 329f76ee892STomi Valkeinen if (r) 330f76ee892STomi Valkeinen return r; 331f76ee892STomi Valkeinen } else { 332f76ee892STomi Valkeinen return -ENODEV; 333f76ee892STomi Valkeinen } 334f76ee892STomi Valkeinen 335f76ee892STomi Valkeinen if (gpio_is_valid(ddata->backlight_gpio)) { 336f76ee892STomi Valkeinen r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio, 337f76ee892STomi Valkeinen GPIOF_OUT_INIT_LOW, "panel backlight"); 338f76ee892STomi Valkeinen if (r) 339f76ee892STomi Valkeinen goto err_gpio; 340f76ee892STomi Valkeinen } 341f76ee892STomi Valkeinen 342f76ee892STomi Valkeinen ddata->videomode = lb035q02_timings; 343f76ee892STomi Valkeinen 344f76ee892STomi Valkeinen dssdev = &ddata->dssdev; 345f76ee892STomi Valkeinen dssdev->dev = &spi->dev; 346f76ee892STomi Valkeinen dssdev->driver = &lb035q02_ops; 347f76ee892STomi Valkeinen dssdev->type = OMAP_DISPLAY_TYPE_DPI; 348f76ee892STomi Valkeinen dssdev->owner = THIS_MODULE; 349f76ee892STomi Valkeinen dssdev->panel.timings = ddata->videomode; 350f76ee892STomi Valkeinen dssdev->phy.dpi.data_lines = ddata->data_lines; 351f76ee892STomi Valkeinen 352f76ee892STomi Valkeinen r = omapdss_register_display(dssdev); 353f76ee892STomi Valkeinen if (r) { 354f76ee892STomi Valkeinen dev_err(&spi->dev, "Failed to register panel\n"); 355f76ee892STomi Valkeinen goto err_reg; 356f76ee892STomi Valkeinen } 357f76ee892STomi Valkeinen 358f76ee892STomi Valkeinen return 0; 359f76ee892STomi Valkeinen 360f76ee892STomi Valkeinen err_reg: 361f76ee892STomi Valkeinen err_gpio: 362f76ee892STomi Valkeinen omap_dss_put_device(ddata->in); 363f76ee892STomi Valkeinen return r; 364f76ee892STomi Valkeinen } 365f76ee892STomi Valkeinen 366f76ee892STomi Valkeinen static int lb035q02_panel_spi_remove(struct spi_device *spi) 367f76ee892STomi Valkeinen { 368f76ee892STomi Valkeinen struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); 369f76ee892STomi Valkeinen struct omap_dss_device *dssdev = &ddata->dssdev; 370f76ee892STomi Valkeinen struct omap_dss_device *in = ddata->in; 371f76ee892STomi Valkeinen 372f76ee892STomi Valkeinen omapdss_unregister_display(dssdev); 373f76ee892STomi Valkeinen 374f76ee892STomi Valkeinen lb035q02_disable(dssdev); 375f76ee892STomi Valkeinen lb035q02_disconnect(dssdev); 376f76ee892STomi Valkeinen 377f76ee892STomi Valkeinen omap_dss_put_device(in); 378f76ee892STomi Valkeinen 379f76ee892STomi Valkeinen return 0; 380f76ee892STomi Valkeinen } 381f76ee892STomi Valkeinen 382f76ee892STomi Valkeinen static const struct of_device_id lb035q02_of_match[] = { 383f76ee892STomi Valkeinen { .compatible = "omapdss,lgphilips,lb035q02", }, 384f76ee892STomi Valkeinen {}, 385f76ee892STomi Valkeinen }; 386f76ee892STomi Valkeinen 387f76ee892STomi Valkeinen MODULE_DEVICE_TABLE(of, lb035q02_of_match); 388f76ee892STomi Valkeinen 389f76ee892STomi Valkeinen static struct spi_driver lb035q02_spi_driver = { 390f76ee892STomi Valkeinen .probe = lb035q02_panel_spi_probe, 391f76ee892STomi Valkeinen .remove = lb035q02_panel_spi_remove, 392f76ee892STomi Valkeinen .driver = { 393f76ee892STomi Valkeinen .name = "panel_lgphilips_lb035q02", 394f76ee892STomi Valkeinen .of_match_table = lb035q02_of_match, 395f76ee892STomi Valkeinen .suppress_bind_attrs = true, 396f76ee892STomi Valkeinen }, 397f76ee892STomi Valkeinen }; 398f76ee892STomi Valkeinen 399f76ee892STomi Valkeinen module_spi_driver(lb035q02_spi_driver); 400f76ee892STomi Valkeinen 401f76ee892STomi Valkeinen MODULE_ALIAS("spi:lgphilips,lb035q02"); 402f76ee892STomi Valkeinen MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); 403f76ee892STomi Valkeinen MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver"); 404f76ee892STomi Valkeinen MODULE_LICENSE("GPL"); 405