1/* 2 * LCD panel driver for Sharp LS037V7DW01 3 * 4 * Copyright (C) 2008 Nokia Corporation 5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20#include <linux/module.h> 21#include <linux/delay.h> 22#include <linux/device.h> 23#include <linux/backlight.h> 24#include <linux/fb.h> 25#include <linux/err.h> 26#include <linux/slab.h> 27 28#include <plat/display.h> 29 30struct sharp_data { 31 struct backlight_device *bl; 32}; 33 34static struct omap_video_timings sharp_ls_timings = { 35 .x_res = 480, 36 .y_res = 640, 37 38 .pixel_clock = 19200, 39 40 .hsw = 2, 41 .hfp = 1, 42 .hbp = 28, 43 44 .vsw = 1, 45 .vfp = 1, 46 .vbp = 1, 47}; 48 49static int sharp_ls_bl_update_status(struct backlight_device *bl) 50{ 51 struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev); 52 int level; 53 54 if (!dssdev->set_backlight) 55 return -EINVAL; 56 57 if (bl->props.fb_blank == FB_BLANK_UNBLANK && 58 bl->props.power == FB_BLANK_UNBLANK) 59 level = bl->props.brightness; 60 else 61 level = 0; 62 63 return dssdev->set_backlight(dssdev, level); 64} 65 66static int sharp_ls_bl_get_brightness(struct backlight_device *bl) 67{ 68 if (bl->props.fb_blank == FB_BLANK_UNBLANK && 69 bl->props.power == FB_BLANK_UNBLANK) 70 return bl->props.brightness; 71 72 return 0; 73} 74 75static const struct backlight_ops sharp_ls_bl_ops = { 76 .get_brightness = sharp_ls_bl_get_brightness, 77 .update_status = sharp_ls_bl_update_status, 78}; 79 80 81 82static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) 83{ 84 struct backlight_properties props; 85 struct backlight_device *bl; 86 struct sharp_data *sd; 87 int r; 88 89 dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | 90 OMAP_DSS_LCD_IHS; 91 dssdev->panel.acb = 0x28; 92 dssdev->panel.timings = sharp_ls_timings; 93 94 sd = kzalloc(sizeof(*sd), GFP_KERNEL); 95 if (!sd) 96 return -ENOMEM; 97 98 dev_set_drvdata(&dssdev->dev, sd); 99 100 memset(&props, 0, sizeof(struct backlight_properties)); 101 props.max_brightness = dssdev->max_backlight_level; 102 103 bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev, 104 &sharp_ls_bl_ops, &props); 105 if (IS_ERR(bl)) { 106 r = PTR_ERR(bl); 107 kfree(sd); 108 return r; 109 } 110 sd->bl = bl; 111 112 bl->props.fb_blank = FB_BLANK_UNBLANK; 113 bl->props.power = FB_BLANK_UNBLANK; 114 bl->props.brightness = dssdev->max_backlight_level; 115 r = sharp_ls_bl_update_status(bl); 116 if (r < 0) 117 dev_err(&dssdev->dev, "failed to set lcd brightness\n"); 118 119 return 0; 120} 121 122static void sharp_ls_panel_remove(struct omap_dss_device *dssdev) 123{ 124 struct sharp_data *sd = dev_get_drvdata(&dssdev->dev); 125 struct backlight_device *bl = sd->bl; 126 127 bl->props.power = FB_BLANK_POWERDOWN; 128 sharp_ls_bl_update_status(bl); 129 backlight_device_unregister(bl); 130 131 kfree(sd); 132} 133 134static int sharp_ls_power_on(struct omap_dss_device *dssdev) 135{ 136 int r = 0; 137 138 r = omapdss_dpi_display_enable(dssdev); 139 if (r) 140 goto err0; 141 142 /* wait couple of vsyncs until enabling the LCD */ 143 msleep(50); 144 145 if (dssdev->platform_enable) { 146 r = dssdev->platform_enable(dssdev); 147 if (r) 148 goto err1; 149 } 150 151 return 0; 152err1: 153 omapdss_dpi_display_disable(dssdev); 154err0: 155 return r; 156} 157 158static void sharp_ls_power_off(struct omap_dss_device *dssdev) 159{ 160 if (dssdev->platform_disable) 161 dssdev->platform_disable(dssdev); 162 163 /* wait at least 5 vsyncs after disabling the LCD */ 164 165 msleep(100); 166 167 omapdss_dpi_display_disable(dssdev); 168} 169 170static int sharp_ls_panel_enable(struct omap_dss_device *dssdev) 171{ 172 int r; 173 r = sharp_ls_power_on(dssdev); 174 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 175 return r; 176} 177 178static void sharp_ls_panel_disable(struct omap_dss_device *dssdev) 179{ 180 sharp_ls_power_off(dssdev); 181 dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 182} 183 184static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev) 185{ 186 sharp_ls_power_off(dssdev); 187 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; 188 return 0; 189} 190 191static int sharp_ls_panel_resume(struct omap_dss_device *dssdev) 192{ 193 int r; 194 r = sharp_ls_power_on(dssdev); 195 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 196 return r; 197} 198 199static struct omap_dss_driver sharp_ls_driver = { 200 .probe = sharp_ls_panel_probe, 201 .remove = sharp_ls_panel_remove, 202 203 .enable = sharp_ls_panel_enable, 204 .disable = sharp_ls_panel_disable, 205 .suspend = sharp_ls_panel_suspend, 206 .resume = sharp_ls_panel_resume, 207 208 .driver = { 209 .name = "sharp_ls_panel", 210 .owner = THIS_MODULE, 211 }, 212}; 213 214static int __init sharp_ls_panel_drv_init(void) 215{ 216 return omap_dss_register_driver(&sharp_ls_driver); 217} 218 219static void __exit sharp_ls_panel_drv_exit(void) 220{ 221 omap_dss_unregister_driver(&sharp_ls_driver); 222} 223 224module_init(sharp_ls_panel_drv_init); 225module_exit(sharp_ls_panel_drv_exit); 226MODULE_LICENSE("GPL"); 227