1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Backlight driver for OMAP based boards. 4 * 5 * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org> 6 */ 7 8 #include <linux/module.h> 9 #include <linux/kernel.h> 10 #include <linux/init.h> 11 #include <linux/platform_device.h> 12 #include <linux/fb.h> 13 #include <linux/backlight.h> 14 #include <linux/slab.h> 15 #include <linux/platform_data/omap1_bl.h> 16 17 #include <mach/hardware.h> 18 #include <mach/mux.h> 19 20 #define OMAPBL_MAX_INTENSITY 0xff 21 22 struct omap_backlight { 23 int powermode; 24 int current_intensity; 25 26 struct device *dev; 27 struct omap_backlight_config *pdata; 28 }; 29 30 static inline void omapbl_send_intensity(int intensity) 31 { 32 omap_writeb(intensity, OMAP_PWL_ENABLE); 33 } 34 35 static inline void omapbl_send_enable(int enable) 36 { 37 omap_writeb(enable, OMAP_PWL_CLK_ENABLE); 38 } 39 40 static void omapbl_blank(struct omap_backlight *bl, int mode) 41 { 42 if (bl->pdata->set_power) 43 bl->pdata->set_power(bl->dev, mode); 44 45 switch (mode) { 46 case FB_BLANK_NORMAL: 47 case FB_BLANK_VSYNC_SUSPEND: 48 case FB_BLANK_HSYNC_SUSPEND: 49 case FB_BLANK_POWERDOWN: 50 omapbl_send_intensity(0); 51 omapbl_send_enable(0); 52 break; 53 54 case FB_BLANK_UNBLANK: 55 omapbl_send_intensity(bl->current_intensity); 56 omapbl_send_enable(1); 57 break; 58 } 59 } 60 61 #ifdef CONFIG_PM_SLEEP 62 static int omapbl_suspend(struct device *dev) 63 { 64 struct backlight_device *bl_dev = dev_get_drvdata(dev); 65 struct omap_backlight *bl = bl_get_data(bl_dev); 66 67 omapbl_blank(bl, FB_BLANK_POWERDOWN); 68 return 0; 69 } 70 71 static int omapbl_resume(struct device *dev) 72 { 73 struct backlight_device *bl_dev = dev_get_drvdata(dev); 74 struct omap_backlight *bl = bl_get_data(bl_dev); 75 76 omapbl_blank(bl, bl->powermode); 77 return 0; 78 } 79 #endif 80 81 static int omapbl_set_power(struct backlight_device *dev, int state) 82 { 83 struct omap_backlight *bl = bl_get_data(dev); 84 85 omapbl_blank(bl, state); 86 bl->powermode = state; 87 88 return 0; 89 } 90 91 static int omapbl_update_status(struct backlight_device *dev) 92 { 93 struct omap_backlight *bl = bl_get_data(dev); 94 95 if (bl->current_intensity != dev->props.brightness) { 96 if (bl->powermode == FB_BLANK_UNBLANK) 97 omapbl_send_intensity(dev->props.brightness); 98 bl->current_intensity = dev->props.brightness; 99 } 100 101 if (dev->props.fb_blank != bl->powermode) 102 omapbl_set_power(dev, dev->props.fb_blank); 103 104 return 0; 105 } 106 107 static int omapbl_get_intensity(struct backlight_device *dev) 108 { 109 struct omap_backlight *bl = bl_get_data(dev); 110 111 return bl->current_intensity; 112 } 113 114 static const struct backlight_ops omapbl_ops = { 115 .get_brightness = omapbl_get_intensity, 116 .update_status = omapbl_update_status, 117 }; 118 119 static int omapbl_probe(struct platform_device *pdev) 120 { 121 struct backlight_properties props; 122 struct backlight_device *dev; 123 struct omap_backlight *bl; 124 struct omap_backlight_config *pdata = dev_get_platdata(&pdev->dev); 125 126 if (!pdata) 127 return -ENXIO; 128 129 bl = devm_kzalloc(&pdev->dev, sizeof(struct omap_backlight), 130 GFP_KERNEL); 131 if (unlikely(!bl)) 132 return -ENOMEM; 133 134 memset(&props, 0, sizeof(struct backlight_properties)); 135 props.type = BACKLIGHT_RAW; 136 props.max_brightness = OMAPBL_MAX_INTENSITY; 137 dev = devm_backlight_device_register(&pdev->dev, "omap-bl", &pdev->dev, 138 bl, &omapbl_ops, &props); 139 if (IS_ERR(dev)) 140 return PTR_ERR(dev); 141 142 bl->powermode = FB_BLANK_POWERDOWN; 143 bl->current_intensity = 0; 144 145 bl->pdata = pdata; 146 bl->dev = &pdev->dev; 147 148 platform_set_drvdata(pdev, dev); 149 150 omap_cfg_reg(PWL); /* Conflicts with UART3 */ 151 152 dev->props.fb_blank = FB_BLANK_UNBLANK; 153 dev->props.brightness = pdata->default_intensity; 154 omapbl_update_status(dev); 155 156 dev_info(&pdev->dev, "OMAP LCD backlight initialised\n"); 157 158 return 0; 159 } 160 161 static SIMPLE_DEV_PM_OPS(omapbl_pm_ops, omapbl_suspend, omapbl_resume); 162 163 static struct platform_driver omapbl_driver = { 164 .probe = omapbl_probe, 165 .driver = { 166 .name = "omap-bl", 167 .pm = &omapbl_pm_ops, 168 }, 169 }; 170 171 module_platform_driver(omapbl_driver); 172 173 MODULE_AUTHOR("Andrzej Zaborowski <balrog@zabor.org>"); 174 MODULE_DESCRIPTION("OMAP LCD Backlight driver"); 175 MODULE_LICENSE("GPL"); 176