1 /* 2 * Backlight driver for Dialog Semiconductor DA9030/DA9034 3 * 4 * Copyright (C) 2008 Compulab, Ltd. 5 * Mike Rapoport <mike@compulab.co.il> 6 * 7 * Copyright (C) 2006-2008 Marvell International Ltd. 8 * Eric Miao <eric.miao@marvell.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15 #include <linux/kernel.h> 16 #include <linux/init.h> 17 #include <linux/platform_device.h> 18 #include <linux/fb.h> 19 #include <linux/backlight.h> 20 #include <linux/mfd/da903x.h> 21 22 #define DA9030_WLED_CONTROL 0x25 23 #define DA9030_WLED_CP_EN (1 << 6) 24 #define DA9030_WLED_TRIM(x) ((x) & 0x7) 25 26 #define DA9034_WLED_CONTROL1 0x3C 27 #define DA9034_WLED_CONTROL2 0x3D 28 29 #define DA9034_WLED_BOOST_EN (1 << 5) 30 31 #define DA9030_MAX_BRIGHTNESS 7 32 #define DA9034_MAX_BRIGHTNESS 0x7f 33 34 struct da903x_backlight_data { 35 struct device *da903x_dev; 36 int id; 37 int current_brightness; 38 }; 39 40 static int da903x_backlight_set(struct backlight_device *bl, int brightness) 41 { 42 struct da903x_backlight_data *data = bl_get_data(bl); 43 struct device *dev = data->da903x_dev; 44 uint8_t val; 45 int ret = 0; 46 47 switch (data->id) { 48 case DA9034_ID_WLED: 49 ret = da903x_update(dev, DA9034_WLED_CONTROL1, 50 brightness, 0x7f); 51 if (ret) 52 return ret; 53 54 if (data->current_brightness && brightness == 0) 55 ret = da903x_clr_bits(dev, 56 DA9034_WLED_CONTROL2, 57 DA9034_WLED_BOOST_EN); 58 59 if (data->current_brightness == 0 && brightness) 60 ret = da903x_set_bits(dev, 61 DA9034_WLED_CONTROL2, 62 DA9034_WLED_BOOST_EN); 63 break; 64 case DA9030_ID_WLED: 65 val = DA9030_WLED_TRIM(brightness); 66 val |= brightness ? DA9030_WLED_CP_EN : 0; 67 ret = da903x_write(dev, DA9030_WLED_CONTROL, val); 68 break; 69 } 70 71 if (ret) 72 return ret; 73 74 data->current_brightness = brightness; 75 return 0; 76 } 77 78 static int da903x_backlight_update_status(struct backlight_device *bl) 79 { 80 int brightness = bl->props.brightness; 81 82 if (bl->props.power != FB_BLANK_UNBLANK) 83 brightness = 0; 84 85 if (bl->props.fb_blank != FB_BLANK_UNBLANK) 86 brightness = 0; 87 88 return da903x_backlight_set(bl, brightness); 89 } 90 91 static int da903x_backlight_get_brightness(struct backlight_device *bl) 92 { 93 struct da903x_backlight_data *data = bl_get_data(bl); 94 return data->current_brightness; 95 } 96 97 static struct backlight_ops da903x_backlight_ops = { 98 .update_status = da903x_backlight_update_status, 99 .get_brightness = da903x_backlight_get_brightness, 100 }; 101 102 static int da903x_backlight_probe(struct platform_device *pdev) 103 { 104 struct da903x_backlight_data *data; 105 struct backlight_device *bl; 106 int max_brightness; 107 108 data = kzalloc(sizeof(*data), GFP_KERNEL); 109 if (data == NULL) 110 return -ENOMEM; 111 112 switch (pdev->id) { 113 case DA9030_ID_WLED: 114 max_brightness = DA9030_MAX_BRIGHTNESS; 115 break; 116 case DA9034_ID_WLED: 117 max_brightness = DA9034_MAX_BRIGHTNESS; 118 break; 119 default: 120 dev_err(&pdev->dev, "invalid backlight device ID(%d)\n", 121 pdev->id); 122 kfree(data); 123 return -EINVAL; 124 } 125 126 data->id = pdev->id; 127 data->da903x_dev = pdev->dev.parent; 128 data->current_brightness = 0; 129 130 bl = backlight_device_register(pdev->name, data->da903x_dev, 131 data, &da903x_backlight_ops); 132 if (IS_ERR(bl)) { 133 dev_err(&pdev->dev, "failed to register backlight\n"); 134 kfree(data); 135 return PTR_ERR(bl); 136 } 137 138 bl->props.max_brightness = max_brightness; 139 bl->props.brightness = max_brightness; 140 141 platform_set_drvdata(pdev, bl); 142 backlight_update_status(bl); 143 return 0; 144 } 145 146 static int da903x_backlight_remove(struct platform_device *pdev) 147 { 148 struct backlight_device *bl = platform_get_drvdata(pdev); 149 struct da903x_backlight_data *data = bl_get_data(bl); 150 151 backlight_device_unregister(bl); 152 kfree(data); 153 return 0; 154 } 155 156 #ifdef CONFIG_PM 157 static int da903x_backlight_suspend(struct platform_device *pdev, 158 pm_message_t state) 159 { 160 struct backlight_device *bl = platform_get_drvdata(pdev); 161 return da903x_backlight_set(bl, 0); 162 } 163 164 static int da903x_backlight_resume(struct platform_device *pdev) 165 { 166 struct backlight_device *bl = platform_get_drvdata(pdev); 167 168 backlight_update_status(bl); 169 return 0; 170 } 171 #else 172 #define da903x_backlight_suspend NULL 173 #define da903x_backlight_resume NULL 174 #endif 175 176 static struct platform_driver da903x_backlight_driver = { 177 .driver = { 178 .name = "da903x-backlight", 179 .owner = THIS_MODULE, 180 }, 181 .probe = da903x_backlight_probe, 182 .remove = da903x_backlight_remove, 183 .suspend = da903x_backlight_suspend, 184 .resume = da903x_backlight_resume, 185 }; 186 187 static int __init da903x_backlight_init(void) 188 { 189 return platform_driver_register(&da903x_backlight_driver); 190 } 191 module_init(da903x_backlight_init); 192 193 static void __exit da903x_backlight_exit(void) 194 { 195 platform_driver_unregister(&da903x_backlight_driver); 196 } 197 module_exit(da903x_backlight_exit); 198 199 MODULE_DESCRIPTION("Backlight Driver for Dialog Semiconductor DA9030/DA9034"); 200 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>" 201 "Mike Rapoport <mike@compulab.co.il>"); 202 MODULE_LICENSE("GPL"); 203 MODULE_ALIAS("platform:da903x-backlight"); 204