12ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen/* 22ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> 32ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * PCF50633 backlight device driver 42ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * 52ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * This program is free software; you can redistribute it and/or modify it 62ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * under the terms of the GNU General Public License as published by the 72ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * Free Software Foundation; either version 2 of the License, or (at your 82ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * option) any later version. 92ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * 102ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * You should have received a copy of the GNU General Public License along 112ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * with this program; if not, write to the Free Software Foundation, Inc., 122ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * 675 Mass Ave, Cambridge, MA 02139, USA. 132ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * 142ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen */ 152ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 162ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen#include <linux/kernel.h> 172ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen#include <linux/module.h> 182ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen#include <linux/slab.h> 192ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen#include <linux/platform_device.h> 202ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 212ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen#include <linux/backlight.h> 222ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen#include <linux/fb.h> 232ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 242ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen#include <linux/mfd/pcf50633/core.h> 252ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen#include <linux/mfd/pcf50633/backlight.h> 262ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 272ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausenstruct pcf50633_bl { 282ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct pcf50633 *pcf; 292ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct backlight_device *bl; 302ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 312ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen unsigned int brightness; 322ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen unsigned int brightness_limit; 332ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen}; 342ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 352ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen/* 362ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * pcf50633_bl_set_brightness_limit 372ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * 382ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * Update the brightness limit for the pc50633 backlight. The actual brightness 392ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * will not go above the limit. This is useful to limit power drain for example 402ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * on low battery. 412ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * 422ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * @dev: Pointer to a pcf50633 device 432ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * @limit: The brightness limit. Valid values are 0-63 442ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen */ 452ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausenint pcf50633_bl_set_brightness_limit(struct pcf50633 *pcf, unsigned int limit) 462ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen{ 472ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct pcf50633_bl *pcf_bl = platform_get_drvdata(pcf->bl_pdev); 482ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 492ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen if (!pcf_bl) 502ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen return -ENODEV; 512ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 522ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf_bl->brightness_limit = limit & 0x3f; 532ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen backlight_update_status(pcf_bl->bl); 542ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 552ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen return 0; 562ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen} 572ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 582ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausenstatic int pcf50633_bl_update_status(struct backlight_device *bl) 592ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen{ 602ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct pcf50633_bl *pcf_bl = bl_get_data(bl); 612ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen unsigned int new_brightness; 622ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 632ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 642ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK) || 652ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen bl->props.power != FB_BLANK_UNBLANK) 662ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen new_brightness = 0; 672ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen else if (bl->props.brightness < pcf_bl->brightness_limit) 682ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen new_brightness = bl->props.brightness; 692ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen else 702ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen new_brightness = pcf_bl->brightness_limit; 712ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 722ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 732ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen if (pcf_bl->brightness == new_brightness) 742ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen return 0; 752ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 762ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen if (new_brightness) { 772ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDOUT, 782ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen new_brightness); 792ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen if (!pcf_bl->brightness) 802ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 1); 812ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen } else { 822ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 0); 832ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen } 842ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 852ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf_bl->brightness = new_brightness; 862ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 872ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen return 0; 882ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen} 892ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 902ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausenstatic int pcf50633_bl_get_brightness(struct backlight_device *bl) 912ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen{ 922ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct pcf50633_bl *pcf_bl = bl_get_data(bl); 932ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen return pcf_bl->brightness; 942ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen} 952ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 962ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausenstatic const struct backlight_ops pcf50633_bl_ops = { 972ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen .get_brightness = pcf50633_bl_get_brightness, 982ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen .update_status = pcf50633_bl_update_status, 992ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen .options = BL_CORE_SUSPENDRESUME, 1002ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen}; 1012ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1022ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausenstatic int __devinit pcf50633_bl_probe(struct platform_device *pdev) 1032ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen{ 1042ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct pcf50633_bl *pcf_bl; 1052ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct device *parent = pdev->dev.parent; 1062ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct pcf50633_platform_data *pcf50633_data = parent->platform_data; 1072ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data; 1082ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct backlight_properties bl_props; 1092ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 110ce969228fdb54a7e3d7cc1ed27367fd4b9525d74Julia Lawall pcf_bl = devm_kzalloc(&pdev->dev, sizeof(*pcf_bl), GFP_KERNEL); 1112ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen if (!pcf_bl) 1122ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen return -ENOMEM; 1132ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 114bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett bl_props.type = BACKLIGHT_RAW; 1152ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen bl_props.max_brightness = 0x3f; 1162ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen bl_props.power = FB_BLANK_UNBLANK; 1172ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1182ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen if (pdata) { 1192ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen bl_props.brightness = pdata->default_brightness; 1202ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf_bl->brightness_limit = pdata->default_brightness_limit; 1212ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen } else { 1222ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen bl_props.brightness = 0x3f; 1232ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf_bl->brightness_limit = 0x3f; 1242ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen } 1252ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1262ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf_bl->pcf = dev_to_pcf50633(pdev->dev.parent); 1272ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1282ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl, 1292ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen &pcf50633_bl_ops, &bl_props); 1302ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 131ce969228fdb54a7e3d7cc1ed27367fd4b9525d74Julia Lawall if (IS_ERR(pcf_bl->bl)) 132ce969228fdb54a7e3d7cc1ed27367fd4b9525d74Julia Lawall return PTR_ERR(pcf_bl->bl); 1332ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1342ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen platform_set_drvdata(pdev, pcf_bl); 1352ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1362ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDDIM, pdata->ramp_time); 1372ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1382ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen /* Should be different from bl_props.brightness, so we do not exit 1392ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen * update_status early the first time it's called */ 1402ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen pcf_bl->brightness = pcf_bl->bl->props.brightness + 1; 1412ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1422ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen backlight_update_status(pcf_bl->bl); 1432ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1442ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen return 0; 1452ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen} 1462ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1472ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausenstatic int __devexit pcf50633_bl_remove(struct platform_device *pdev) 1482ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen{ 1492ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen struct pcf50633_bl *pcf_bl = platform_get_drvdata(pdev); 1502ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1512ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen backlight_device_unregister(pcf_bl->bl); 1522ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1532ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen platform_set_drvdata(pdev, NULL); 1542ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1552ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen return 0; 1562ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen} 1572ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1582ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausenstatic struct platform_driver pcf50633_bl_driver = { 1592ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen .probe = pcf50633_bl_probe, 1602ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen .remove = __devexit_p(pcf50633_bl_remove), 1612ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen .driver = { 1622ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen .name = "pcf50633-backlight", 1632ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen }, 1642ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen}; 1652ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 16681178e021689bf86c328f144aa0f0e1b50f5e94cAxel Linmodule_platform_driver(pcf50633_bl_driver); 1672ddfd12f3584840f5190897214423061d8a0602fLars-Peter Clausen 1682ddfd12f3584840f5190897214423061d8a0602fLars-Peter ClausenMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 1692ddfd12f3584840f5190897214423061d8a0602fLars-Peter ClausenMODULE_DESCRIPTION("PCF50633 backlight driver"); 1702ddfd12f3584840f5190897214423061d8a0602fLars-Peter ClausenMODULE_LICENSE("GPL"); 1712ddfd12f3584840f5190897214423061d8a0602fLars-Peter ClausenMODULE_ALIAS("platform:pcf50633-backlight"); 172