Commit cad719d8 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight

* 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight:
  gta02: Use pcf50633 backlight driver instead of platform backlight driver.
  backlight: pcf50633: Register a pcf50633-backlight device in pcf50633 core driver.
  backlight: Add pcf50633 backlight driver
  backlight: 88pm860x_bl: fix error handling in pm860x_backlight_probe
  backlight: max8925_bl: Fix error handling path
  backlight: l4f00242t03: fix error handling in l4f00242t03_probe
  backlight: add S6E63M0 AMOLED LCD Panel driver
  backlight: adp8860: add support for ADP8861 & ADP8863
  backlight: mbp_nvidia_bl - Fix DMI_SYS_VENDOR for MacBook1,1
  backlight: Add Cirrus EP93xx backlight driver
  backlight: l4f00242t03: Fix regulators handling code in remove function
  backlight: fix adp8860_bl build errors
  backlight: new driver for the ADP8860 backlight parts
  backlight: 88pm860x_bl - potential memory leak
  backlight: mbp_nvidia_bl - add support for older MacBookPro and MacBook 6,1.
  backlight: Kconfig cleanup
  backlight: backlight_device_register() return ERR_PTR()
parents 3ddab478 67e67df8
...@@ -49,7 +49,6 @@ ...@@ -49,7 +49,6 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/backlight.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/mfd/pcf50633/core.h> #include <linux/mfd/pcf50633/core.h>
...@@ -57,6 +56,7 @@ ...@@ -57,6 +56,7 @@
#include <linux/mfd/pcf50633/adc.h> #include <linux/mfd/pcf50633/adc.h>
#include <linux/mfd/pcf50633/gpio.h> #include <linux/mfd/pcf50633/gpio.h>
#include <linux/mfd/pcf50633/pmic.h> #include <linux/mfd/pcf50633/pmic.h>
#include <linux/mfd/pcf50633/backlight.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
...@@ -254,6 +254,12 @@ static char *gta02_batteries[] = { ...@@ -254,6 +254,12 @@ static char *gta02_batteries[] = {
"battery", "battery",
}; };
static struct pcf50633_bl_platform_data gta02_backlight_data = {
.default_brightness = 0x3f,
.default_brightness_limit = 0,
.ramp_time = 5,
};
struct pcf50633_platform_data gta02_pcf_pdata = { struct pcf50633_platform_data gta02_pcf_pdata = {
.resumers = { .resumers = {
[0] = PCF50633_INT1_USBINS | [0] = PCF50633_INT1_USBINS |
...@@ -271,6 +277,8 @@ struct pcf50633_platform_data gta02_pcf_pdata = { ...@@ -271,6 +277,8 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
.charger_reference_current_ma = 1000, .charger_reference_current_ma = 1000,
.backlight_data = &gta02_backlight_data,
.reg_init_data = { .reg_init_data = {
[PCF50633_REGULATOR_AUTO] = { [PCF50633_REGULATOR_AUTO] = {
.constraints = { .constraints = {
...@@ -478,71 +486,6 @@ static struct s3c2410_udc_mach_info gta02_udc_cfg = { ...@@ -478,71 +486,6 @@ static struct s3c2410_udc_mach_info gta02_udc_cfg = {
}; };
static void gta02_bl_set_intensity(int intensity)
{
struct pcf50633 *pcf = gta02_pcf;
int old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);
/* We map 8-bit intensity to 6-bit intensity in hardware. */
intensity >>= 2;
/*
* This can happen during, eg, print of panic on blanked console,
* but we can't service i2c without interrupts active, so abort.
*/
if (in_atomic()) {
printk(KERN_ERR "gta02_bl_set_intensity called while atomic\n");
return;
}
old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);
if (intensity == old_intensity)
return;
/* We can't do this anywhere else. */
pcf50633_reg_write(pcf, PCF50633_REG_LEDDIM, 5);
if (!(pcf50633_reg_read(pcf, PCF50633_REG_LEDENA) & 3))
old_intensity = 0;
/*
* The PCF50633 cannot handle LEDOUT = 0 (datasheet p60)
* if seen, you have to re-enable the LED unit.
*/
if (!intensity || !old_intensity)
pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 0);
/* Illegal to set LEDOUT to 0. */
if (!intensity)
pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f, 2);
else
pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f,
intensity);
if (intensity)
pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 2);
}
static struct generic_bl_info gta02_bl_info = {
.name = "gta02-bl",
.max_intensity = 0xff,
.default_intensity = 0xff,
.set_bl_intensity = gta02_bl_set_intensity,
};
static struct platform_device gta02_bl_dev = {
.name = "generic-bl",
.id = 1,
.dev = {
.platform_data = &gta02_bl_info,
},
};
/* USB */ /* USB */
static struct s3c2410_hcd_info gta02_usb_info __initdata = { static struct s3c2410_hcd_info gta02_usb_info __initdata = {
.port[0] = { .port[0] = {
...@@ -579,7 +522,6 @@ static struct platform_device *gta02_devices[] __initdata = { ...@@ -579,7 +522,6 @@ static struct platform_device *gta02_devices[] __initdata = {
/* These guys DO need to be children of PMU. */ /* These guys DO need to be children of PMU. */
static struct platform_device *gta02_devices_pmu_children[] = { static struct platform_device *gta02_devices_pmu_children[] = {
&gta02_bl_dev,
}; };
......
...@@ -620,6 +620,9 @@ static int __devinit pcf50633_probe(struct i2c_client *client, ...@@ -620,6 +620,9 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
&pcf->mbc_pdev); &pcf->mbc_pdev);
pcf50633_client_dev_register(pcf, "pcf50633-adc", pcf50633_client_dev_register(pcf, "pcf50633-adc",
&pcf->adc_pdev); &pcf->adc_pdev);
pcf50633_client_dev_register(pcf, "pcf50633-backlight",
&pcf->bl_pdev);
for (i = 0; i < PCF50633_NUM_REGULATORS; i++) { for (i = 0; i < PCF50633_NUM_REGULATORS; i++) {
struct platform_device *pdev; struct platform_device *pdev;
......
...@@ -222,6 +222,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) ...@@ -222,6 +222,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
data->port = __check_device(pdata, name); data->port = __check_device(pdata, name);
if (data->port < 0) { if (data->port < 0) {
dev_err(&pdev->dev, "wrong platform data is assigned"); dev_err(&pdev->dev, "wrong platform data is assigned");
kfree(data);
return -EINVAL; return -EINVAL;
} }
...@@ -266,6 +267,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) ...@@ -266,6 +267,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
backlight_update_status(bl); backlight_update_status(bl);
return 0; return 0;
out: out:
backlight_device_unregister(bl);
kfree(data); kfree(data);
return ret; return ret;
} }
......
...@@ -8,12 +8,13 @@ menuconfig BACKLIGHT_LCD_SUPPORT ...@@ -8,12 +8,13 @@ menuconfig BACKLIGHT_LCD_SUPPORT
Enable this to be able to choose the drivers for controlling the Enable this to be able to choose the drivers for controlling the
backlight and the LCD panel on some platforms, for example on PDAs. backlight and the LCD panel on some platforms, for example on PDAs.
if BACKLIGHT_LCD_SUPPORT
# #
# LCD # LCD
# #
config LCD_CLASS_DEVICE config LCD_CLASS_DEVICE
tristate "Lowlevel LCD controls" tristate "Lowlevel LCD controls"
depends on BACKLIGHT_LCD_SUPPORT
default m default m
help help
This framework adds support for low-level control of LCD. This framework adds support for low-level control of LCD.
...@@ -24,31 +25,32 @@ config LCD_CLASS_DEVICE ...@@ -24,31 +25,32 @@ config LCD_CLASS_DEVICE
To have support for your specific LCD panel you will have to To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option. select the proper drivers which depend on this option.
if LCD_CLASS_DEVICE
config LCD_CORGI config LCD_CORGI
tristate "LCD Panel support for SHARP corgi/spitz model" tristate "LCD Panel support for SHARP corgi/spitz model"
depends on LCD_CLASS_DEVICE && SPI_MASTER && PXA_SHARPSL depends on SPI_MASTER && PXA_SHARPSL
help help
Say y here to support the LCD panels usually found on SHARP Say y here to support the LCD panels usually found on SHARP
corgi (C7x0) and spitz (Cxx00) models. corgi (C7x0) and spitz (Cxx00) models.
config LCD_L4F00242T03 config LCD_L4F00242T03
tristate "Epson L4F00242T03 LCD" tristate "Epson L4F00242T03 LCD"
depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO depends on SPI_MASTER && GENERIC_GPIO
help help
SPI driver for Epson L4F00242T03. This provides basic support SPI driver for Epson L4F00242T03. This provides basic support
for init and powering the LCD up/down through a sysfs interface. for init and powering the LCD up/down through a sysfs interface.
config LCD_LMS283GF05 config LCD_LMS283GF05
tristate "Samsung LMS283GF05 LCD" tristate "Samsung LMS283GF05 LCD"
depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO depends on SPI_MASTER && GENERIC_GPIO
help help
SPI driver for Samsung LMS283GF05. This provides basic support SPI driver for Samsung LMS283GF05. This provides basic support
for powering the LCD up/down through a sysfs interface. for powering the LCD up/down through a sysfs interface.
config LCD_LTV350QV config LCD_LTV350QV
tristate "Samsung LTV350QV LCD Panel" tristate "Samsung LTV350QV LCD Panel"
depends on LCD_CLASS_DEVICE && SPI_MASTER depends on SPI_MASTER
default n
help help
If you have a Samsung LTV350QV LCD panel, say y to include a If you have a Samsung LTV350QV LCD panel, say y to include a
power control driver for it. The panel starts up in power power control driver for it. The panel starts up in power
...@@ -59,60 +61,61 @@ config LCD_LTV350QV ...@@ -59,60 +61,61 @@ config LCD_LTV350QV
config LCD_ILI9320 config LCD_ILI9320
tristate tristate
depends on LCD_CLASS_DEVICE && BACKLIGHT_LCD_SUPPORT
default n
help help
If you have a panel based on the ILI9320 controller chip If you have a panel based on the ILI9320 controller chip
then say y to include a power driver for it. then say y to include a power driver for it.
config LCD_TDO24M config LCD_TDO24M
tristate "Toppoly TDO24M and TDO35S LCD Panels support" tristate "Toppoly TDO24M and TDO35S LCD Panels support"
depends on LCD_CLASS_DEVICE && SPI_MASTER depends on SPI_MASTER
default n
help help
If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to
include the support for it. include the support for it.
config LCD_VGG2432A4 config LCD_VGG2432A4
tristate "VGG2432A4 LCM device support" tristate "VGG2432A4 LCM device support"
depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER depends on SPI_MASTER
select LCD_ILI9320 select LCD_ILI9320
default n
help help
If you have a VGG2432A4 panel based on the ILI9320 controller chip If you have a VGG2432A4 panel based on the ILI9320 controller chip
then say y to include a power driver for it. then say y to include a power driver for it.
config LCD_PLATFORM config LCD_PLATFORM
tristate "Platform LCD controls" tristate "Platform LCD controls"
depends on LCD_CLASS_DEVICE
help help
This driver provides a platform-device registered LCD power This driver provides a platform-device registered LCD power
control interface. control interface.
config LCD_TOSA config LCD_TOSA
tristate "Sharp SL-6000 LCD Driver" tristate "Sharp SL-6000 LCD Driver"
depends on LCD_CLASS_DEVICE && SPI depends on SPI && MACH_TOSA
depends on MACH_TOSA
default n
help help
If you have an Sharp SL-6000 Zaurus say Y to enable a driver If you have an Sharp SL-6000 Zaurus say Y to enable a driver
for its LCD. for its LCD.
config LCD_HP700 config LCD_HP700
tristate "HP Jornada 700 series LCD Driver" tristate "HP Jornada 700 series LCD Driver"
depends on LCD_CLASS_DEVICE
depends on SA1100_JORNADA720_SSP && !PREEMPT depends on SA1100_JORNADA720_SSP && !PREEMPT
default y default y
help help
If you have an HP Jornada 700 series handheld (710/720/728) If you have an HP Jornada 700 series handheld (710/720/728)
say Y to enable LCD control driver. say Y to enable LCD control driver.
config LCD_S6E63M0
tristate "S6E63M0 AMOLED LCD Driver"
depends on SPI && BACKLIGHT_CLASS_DEVICE
default n
help
If you have an S6E63M0 LCD Panel, say Y to enable its
LCD control driver.
endif # LCD_CLASS_DEVICE
# #
# Backlight # Backlight
# #
config BACKLIGHT_CLASS_DEVICE config BACKLIGHT_CLASS_DEVICE
tristate "Lowlevel Backlight controls" tristate "Lowlevel Backlight controls"
depends on BACKLIGHT_LCD_SUPPORT
default m default m
help help
This framework adds support for low-level control of the LCD This framework adds support for low-level control of the LCD
...@@ -121,9 +124,11 @@ config BACKLIGHT_CLASS_DEVICE ...@@ -121,9 +124,11 @@ config BACKLIGHT_CLASS_DEVICE
To have support for your specific LCD panel you will have to To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option. select the proper drivers which depend on this option.
if BACKLIGHT_CLASS_DEVICE
config BACKLIGHT_ATMEL_LCDC config BACKLIGHT_ATMEL_LCDC
bool "Atmel LCDC Contrast-as-Backlight control" bool "Atmel LCDC Contrast-as-Backlight control"
depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL depends on FB_ATMEL
default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK
help help
This provides a backlight control internal to the Atmel LCDC This provides a backlight control internal to the Atmel LCDC
...@@ -136,8 +141,7 @@ config BACKLIGHT_ATMEL_LCDC ...@@ -136,8 +141,7 @@ config BACKLIGHT_ATMEL_LCDC
config BACKLIGHT_ATMEL_PWM config BACKLIGHT_ATMEL_PWM
tristate "Atmel PWM backlight control" tristate "Atmel PWM backlight control"
depends on BACKLIGHT_CLASS_DEVICE && ATMEL_PWM depends on ATMEL_PWM
default n
help help
Say Y here if you want to use the PWM peripheral in Atmel AT91 and Say Y here if you want to use the PWM peripheral in Atmel AT91 and
AVR32 devices. This driver will need additional platform data to know AVR32 devices. This driver will need additional platform data to know
...@@ -146,9 +150,18 @@ config BACKLIGHT_ATMEL_PWM ...@@ -146,9 +150,18 @@ config BACKLIGHT_ATMEL_PWM
To compile this driver as a module, choose M here: the module will be To compile this driver as a module, choose M here: the module will be
called atmel-pwm-bl. called atmel-pwm-bl.
config BACKLIGHT_EP93XX
tristate "Cirrus EP93xx Backlight Driver"
depends on FB_EP93XX
help
If you have a LCD backlight connected to the BRIGHT output of
the EP93xx, say Y here to enable this driver.
To compile this driver as a module, choose M here: the module will
be called ep93xx_bl.
config BACKLIGHT_GENERIC config BACKLIGHT_GENERIC
tristate "Generic (aka Sharp Corgi) Backlight Driver" tristate "Generic (aka Sharp Corgi) Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE
default y default y
help help
Say y to enable the generic platform backlight driver previously Say y to enable the generic platform backlight driver previously
...@@ -157,7 +170,7 @@ config BACKLIGHT_GENERIC ...@@ -157,7 +170,7 @@ config BACKLIGHT_GENERIC
config BACKLIGHT_LOCOMO config BACKLIGHT_LOCOMO
tristate "Sharp LOCOMO LCD/Backlight Driver" tristate "Sharp LOCOMO LCD/Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && SHARP_LOCOMO depends on SHARP_LOCOMO
default y default y
help help
If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
...@@ -165,7 +178,7 @@ config BACKLIGHT_LOCOMO ...@@ -165,7 +178,7 @@ config BACKLIGHT_LOCOMO
config BACKLIGHT_OMAP1 config BACKLIGHT_OMAP1
tristate "OMAP1 PWL-based LCD Backlight" tristate "OMAP1 PWL-based LCD Backlight"
depends on BACKLIGHT_CLASS_DEVICE && ARCH_OMAP1 depends on ARCH_OMAP1
default y default y
help help
This driver controls the LCD backlight level and power for This driver controls the LCD backlight level and power for
...@@ -174,7 +187,7 @@ config BACKLIGHT_OMAP1 ...@@ -174,7 +187,7 @@ config BACKLIGHT_OMAP1
config BACKLIGHT_HP680 config BACKLIGHT_HP680
tristate "HP Jornada 680 Backlight Driver" tristate "HP Jornada 680 Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX depends on SH_HP6XX
default y default y
help help
If you have a HP Jornada 680, say y to enable the If you have a HP Jornada 680, say y to enable the
...@@ -182,7 +195,6 @@ config BACKLIGHT_HP680 ...@@ -182,7 +195,6 @@ config BACKLIGHT_HP680
config BACKLIGHT_HP700 config BACKLIGHT_HP700
tristate "HP Jornada 700 series Backlight Driver" tristate "HP Jornada 700 series Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE
depends on SA1100_JORNADA720_SSP && !PREEMPT depends on SA1100_JORNADA720_SSP && !PREEMPT
default y default y
help help
...@@ -191,76 +203,70 @@ config BACKLIGHT_HP700 ...@@ -191,76 +203,70 @@ config BACKLIGHT_HP700
config BACKLIGHT_PROGEAR config BACKLIGHT_PROGEAR
tristate "Frontpath ProGear Backlight Driver" tristate "Frontpath ProGear Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && PCI && X86 depends on PCI && X86
default n
help help
If you have a Frontpath ProGear say Y to enable the If you have a Frontpath ProGear say Y to enable the
backlight driver. backlight driver.
config BACKLIGHT_CARILLO_RANCH config BACKLIGHT_CARILLO_RANCH
tristate "Intel Carillo Ranch Backlight Driver" tristate "Intel Carillo Ranch Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578
default n
help help
If you have a Intel LE80578 (Carillo Ranch) say Y to enable the If you have a Intel LE80578 (Carillo Ranch) say Y to enable the
backlight driver. backlight driver.
config BACKLIGHT_PWM config BACKLIGHT_PWM
tristate "Generic PWM based Backlight Driver" tristate "Generic PWM based Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && HAVE_PWM depends on HAVE_PWM
help help
If you have a LCD backlight adjustable by PWM, say Y to enable If you have a LCD backlight adjustable by PWM, say Y to enable
this driver. this driver.
config BACKLIGHT_DA903X config BACKLIGHT_DA903X
tristate "Backlight Driver for DA9030/DA9034 using WLED" tristate "Backlight Driver for DA9030/DA9034 using WLED"
depends on BACKLIGHT_CLASS_DEVICE && PMIC_DA903X depends on PMIC_DA903X
help help
If you have a LCD backlight connected to the WLED output of DA9030 If you have a LCD backlight connected to the WLED output of DA9030
or DA9034 WLED output, say Y here to enable this driver. or DA9034 WLED output, say Y here to enable this driver.
config BACKLIGHT_MAX8925 config BACKLIGHT_MAX8925
tristate "Backlight driver for MAX8925" tristate "Backlight driver for MAX8925"
depends on BACKLIGHT_CLASS_DEVICE && MFD_MAX8925 depends on MFD_MAX8925
help help
If you have a LCD backlight connected to the WLED output of MAX8925 If you have a LCD backlight connected to the WLED output of MAX8925
WLED output, say Y here to enable this driver. WLED output, say Y here to enable this driver.
config BACKLIGHT_MBP_NVIDIA config BACKLIGHT_MBP_NVIDIA
tristate "MacBook Pro Nvidia Backlight Driver" tristate "MacBook Pro Nvidia Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && X86 depends on X86
default n
help help
If you have an Apple Macbook Pro with Nvidia graphics hardware say Y If you have an Apple Macbook Pro with Nvidia graphics hardware say Y
to enable a driver for its backlight to enable a driver for its backlight
config BACKLIGHT_TOSA config BACKLIGHT_TOSA
tristate "Sharp SL-6000 Backlight Driver" tristate "Sharp SL-6000 Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && I2C depends on I2C && MACH_TOSA && LCD_TOSA
depends on MACH_TOSA && LCD_TOSA
default n
help help
If you have an Sharp SL-6000 Zaurus say Y to enable a driver If you have an Sharp SL-6000 Zaurus say Y to enable a driver
for its backlight for its backlight
config BACKLIGHT_SAHARA config BACKLIGHT_SAHARA
tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" tristate "Tabletkiosk Sahara Touch-iT Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && X86 depends on X86
default n
help help
If you have a Tabletkiosk Sahara Touch-iT, say y to enable the If you have a Tabletkiosk Sahara Touch-iT, say y to enable the
backlight driver. backlight driver.
config BACKLIGHT_WM831X config BACKLIGHT_WM831X
tristate "WM831x PMIC Backlight Driver" tristate "WM831x PMIC Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && MFD_WM831X depends on MFD_WM831X
help help
If you have a backlight driven by the ISINK and DCDC of a If you have a backlight driven by the ISINK and DCDC of a
WM831x PMIC say y to enable the backlight driver for it. WM831x PMIC say y to enable the backlight driver for it.
config BACKLIGHT_ADX config BACKLIGHT_ADX
tristate "Avionic Design Xanthos Backlight Driver" tristate "Avionic Design Xanthos Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && ARCH_PXA_ADX depends on ARCH_PXA_ADX
default y default y
help help
Say Y to enable the backlight driver on Avionic Design Xanthos-based Say Y to enable the backlight driver on Avionic Design Xanthos-based
...@@ -268,7 +274,7 @@ config BACKLIGHT_ADX ...@@ -268,7 +274,7 @@ config BACKLIGHT_ADX
config BACKLIGHT_ADP5520 config BACKLIGHT_ADP5520
tristate "Backlight Driver for ADP5520/ADP5501 using WLED" tristate "Backlight Driver for ADP5520/ADP5501 using WLED"
depends on BACKLIGHT_CLASS_DEVICE && PMIC_ADP5520 depends on PMIC_ADP5520
help help
If you have a LCD backlight connected to the BST/BL_SNK output of If you have a LCD backlight connected to the BST/BL_SNK output of
ADP5520 or ADP5501, say Y here to enable this driver. ADP5520 or ADP5501, say Y here to enable this driver.
...@@ -276,9 +282,31 @@ config BACKLIGHT_ADP5520 ...@@ -276,9 +282,31 @@ config BACKLIGHT_ADP5520
To compile this driver as a module, choose M here: the module will To compile this driver as a module, choose M here: the module will
be called adp5520_bl. be called adp5520_bl.
config BACKLIGHT_ADP8860
tristate "Backlight Driver for ADP8860/ADP8861/ADP8863 using WLED"
depends on BACKLIGHT_CLASS_DEVICE && I2C
select NEW_LEDS
select LEDS_CLASS
help
If you have a LCD backlight connected to the ADP8860, ADP8861 or
ADP8863 say Y here to enable this driver.
To compile this driver as a module, choose M here: the module will
be called adp8860_bl.
config BACKLIGHT_88PM860X config BACKLIGHT_88PM860X
tristate "Backlight Driver for 88PM8606 using WLED" tristate "Backlight Driver for 88PM8606 using WLED"
depends on BACKLIGHT_CLASS_DEVICE && MFD_88PM860X depends on MFD_88PM860X
help help
Say Y to enable the backlight driver for Marvell 88PM8606. Say Y to enable the backlight driver for Marvell 88PM8606.
config BACKLIGHT_PCF50633
tristate "Backlight driver for NXP PCF50633 MFD"
depends on BACKLIGHT_CLASS_DEVICE && MFD_PCF50633
help
If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
enable its driver.
endif # BACKLIGHT_CLASS_DEVICE
endif # BACKLIGHT_LCD_SUPPORT
...@@ -11,9 +11,11 @@ obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o ...@@ -11,9 +11,11 @@ obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o
obj-$(CONFIG_LCD_TDO24M) += tdo24m.o obj-$(CONFIG_LCD_TDO24M) += tdo24m.o
obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o
obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o
obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o
obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o
obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
...@@ -30,5 +32,7 @@ obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o ...@@ -30,5 +32,7 @@ obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o
obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o
obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o
obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
/*
* Backlight driver for Analog Devices ADP8860 Backlight Devices
*
* Copyright 2009-2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/i2c/adp8860.h>
#define ADP8860_EXT_FEATURES
#define ADP8860_USE_LEDS
#define ADP8860_MFDVID 0x00 /* Manufacturer and device ID */
#define ADP8860_MDCR 0x01 /* Device mode and status */
#define ADP8860_MDCR2 0x02 /* Device mode and Status Register 2 */
#define ADP8860_INTR_EN 0x03 /* Interrupts enable */
#define ADP8860_CFGR 0x04 /* Configuration register */
#define ADP8860_BLSEN 0x05 /* Sink enable backlight or independent */
#define ADP8860_BLOFF 0x06 /* Backlight off timeout */
#define ADP8860_BLDIM 0x07 /* Backlight dim timeout */
#define ADP8860_BLFR 0x08 /* Backlight fade in and out rates */
#define ADP8860_BLMX1 0x09 /* Backlight (Brightness Level 1-daylight) maximum current */
#define ADP8860_BLDM1 0x0A /* Backlight (Brightness Level 1-daylight) dim current */
#define ADP8860_BLMX2 0x0B /* Backlight (Brightness Level 2-office) maximum current */
#define ADP8860_BLDM2 0x0C /* Backlight (Brightness Level 2-office) dim current */
#define ADP8860_BLMX3 0x0D /* Backlight (Brightness Level 3-dark) maximum current */
#define ADP8860_BLDM3 0x0E /* Backlight (Brightness Level 3-dark) dim current */
#define ADP8860_ISCFR 0x0F /* Independent sink current fade control register */
#define ADP8860_ISCC 0x10 /* Independent sink current control register */
#define ADP8860_ISCT1 0x11 /* Independent Sink Current Timer Register LED[7:5] */
#define ADP8860_ISCT2 0x12 /* Independent Sink Current Timer Register LED[4:1] */
#define ADP8860_ISCF 0x13 /* Independent sink current fade register */
#define ADP8860_ISC7 0x14 /* Independent Sink Current LED7 */
#define ADP8860_ISC6 0x15 /* Independent Sink Current LED6 */
#define ADP8860_ISC5 0x16 /* Independent Sink Current LED5 */
#define ADP8860_ISC4 0x17 /* Independent Sink Current LED4 */
#define ADP8860_ISC3 0x18 /* Independent Sink Current LED3 */
#define ADP8860_ISC2 0x19 /* Independent Sink Current LED2 */
#define ADP8860_ISC1 0x1A /* Independent Sink Current LED1 */
#define ADP8860_CCFG 0x1B /* Comparator configuration */
#define ADP8860_CCFG2 0x1C /* Second comparator configuration */
#define ADP8860_L2_TRP 0x1D /* L2 comparator reference */
#define ADP8860_L2_HYS 0x1E /* L2 hysteresis */
#define ADP8860_L3_TRP 0x1F /* L3 comparator reference */
#define ADP8860_L3_HYS 0x20 /* L3 hysteresis */
#define ADP8860_PH1LEVL 0x21 /* First phototransistor ambient light level-low byte register */
#define ADP8860_PH1LEVH 0x22 /* First phototransistor ambient light level-high byte register */
#define ADP8860_PH2LEVL 0x23 /* Second phototransistor ambient light level-low byte register */
#define ADP8860_PH2LEVH 0x24 /* Second phototransistor ambient light level-high byte register */
#define ADP8860_MANUFID 0x0 /* Analog Devices ADP8860 Manufacturer ID */
#define ADP8861_MANUFID 0x4 /* Analog Devices ADP8861 Manufacturer ID */
#define ADP8863_MANUFID 0x2 /* Analog Devices ADP8863 Manufacturer ID */
#define ADP8860_DEVID(x) ((x) & 0xF)
#define ADP8860_MANID(x) ((x) >> 4)
/* MDCR Device mode and status */
#define INT_CFG (1 << 6)
#define NSTBY (1 << 5)
#define DIM_EN (1 << 4)
#define GDWN_DIS (1 << 3)
#define SIS_EN (1 << 2)
#define CMP_AUTOEN (1 << 1)
#define BLEN (1 << 0)
/* ADP8860_CCFG Main ALS comparator level enable */
#define L3_EN (1 << 1)
#define L2_EN (1 << 0)
#define CFGR_BLV_SHIFT 3
#define CFGR_BLV_MASK 0x3
#define ADP8860_FLAG_LED_MASK 0xFF
#define FADE_VAL(in, out) ((0xF & (in)) | ((0xF & (out)) << 4))
#define BL_CFGR_VAL(law, blv) ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1))
#define ALS_CCFG_VAL(filt) ((0x7 & filt) << 5)
enum {
adp8860,
adp8861,
adp8863
};
struct adp8860_led {
struct led_classdev cdev;
struct work_struct work;
struct i2c_client *client;
enum led_brightness new_brightness;
int id;
int flags;
};
struct adp8860_bl {
struct i2c_client *client;
struct backlight_device *bl;
struct adp8860_led *led;
struct adp8860_backlight_platform_data *pdata;
struct mutex lock;
unsigned long cached_daylight_max;
int id;
int revid;
int current_brightness;
unsigned en_ambl_sens:1;
unsigned gdwn_dis:1;
};
static int adp8860_read(struct i2c_client *client, int reg, uint8_t *val)
{
int ret;
ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) {
dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
return ret;
}
*val = (uint8_t)ret;
return 0;
}
static int adp8860_write(struct i2c_client *client, u8 reg, u8 val)
{
return i2c_smbus_write_byte_data(client, reg, val);
}
static int adp8860_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
{
struct adp8860_bl *data = i2c_get_clientdata(client);
uint8_t reg_val;
int ret;
mutex_lock(&data->lock);
ret = adp8860_read(client, reg, &reg_val);
if (!ret && ((reg_val & bit_mask) == 0)) {
reg_val |= bit_mask;
ret = adp8860_write(client, reg, reg_val);
}
mutex_unlock(&data->lock);
return ret;
}
static int adp8860_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
{
struct adp8860_bl *data = i2c_get_clientdata(client);
uint8_t reg_val;
int ret;
mutex_lock(&data->lock);
ret = adp8860_read(client, reg, &reg_val);
if (!ret && (reg_val & bit_mask)) {
reg_val &= ~bit_mask;
ret = adp8860_write(client, reg, reg_val);
}
mutex_unlock(&data->lock);
return ret;
}
/*
* Independent sink / LED
*/
#if defined(ADP8860_USE_LEDS)
static void adp8860_led_work(struct work_struct *work)
{
struct adp8860_led *led = container_of(work, struct adp8860_led, work);
adp8860_write(led->client, ADP8860_ISC1 - led->id + 1,
led->new_brightness >> 1);
}
static void adp8860_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct adp8860_led *led;
led = container_of(led_cdev, struct adp8860_led, cdev);
led->new_brightness = value;
schedule_work(&led->work);
}
static int adp8860_led_setup(struct adp8860_led *led)
{
struct i2c_client *client = led->client;
int ret = 0;
ret = adp8860_write(client, ADP8860_ISC1 - led->id + 1, 0);
ret |= adp8860_set_bits(client, ADP8860_ISCC, 1 << (led->id - 1));
if (led->id > 4)
ret |= adp8860_set_bits(client, ADP8860_ISCT1,
(led->flags & 0x3) << ((led->id - 5) * 2));
else
ret |= adp8860_set_bits(client, ADP8860_ISCT2,
(led->flags & 0x3) << ((led->id - 1) * 2));
return ret;
}
static int __devinit adp8860_led_probe(struct i2c_client *client)
{
struct adp8860_backlight_platform_data *pdata =
client->dev.platform_data;
struct adp8860_bl *data = i2c_get_clientdata(client);
struct adp8860_led *led, *led_dat;
struct led_info *cur_led;
int ret, i;
led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL);
if (led == NULL) {
dev_err(&client->dev, "failed to alloc memory\n");
return -ENOMEM;
}
ret = adp8860_write(client, ADP8860_ISCFR, pdata->led_fade_law);
ret = adp8860_write(client, ADP8860_ISCT1,
(pdata->led_on_time & 0x3) << 6);
ret |= adp8860_write(client, ADP8860_ISCF,
FADE_VAL(pdata->led_fade_in, pdata->led_fade_out));
if (ret) {
dev_err(&client->dev, "failed to write\n");
goto err_free;
}
for (i = 0; i < pdata->num_leds; ++i) {
cur_led = &pdata->leds[i];
led_dat = &led[i];
led_dat->id = cur_led->flags & ADP8860_FLAG_LED_MASK;
if (led_dat->id > 7 || led_dat->id < 1) {
dev_err(&client->dev, "Invalid LED ID %d\n",
led_dat->id);
goto err;
}
if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) {
dev_err(&client->dev, "LED %d used by Backlight\n",
led_dat->id);
goto err;
}
led_dat->cdev.name = cur_led->name;
led_dat->cdev.default_trigger = cur_led->default_trigger;
led_dat->cdev.brightness_set = adp8860_led_set;
led_dat->cdev.brightness = LED_OFF;
led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT;
led_dat->client = client;
led_dat->new_brightness = LED_OFF;
INIT_WORK(&led_dat->work, adp8860_led_work);
ret = led_classdev_register(&client->dev, &led_dat->cdev);
if (ret) {
dev_err(&client->dev, "failed to register LED %d\n",
led_dat->id);
goto err;
}
ret = adp8860_led_setup(led_dat);
if (ret) {
dev_err(&client->dev, "failed to write\n");
i++;
goto err;
}
}
data->led = led;
return 0;
err:
for (i = i - 1; i >= 0; --i) {
led_classdev_unregister(&led[i].cdev);
cancel_work_sync(&led[i].work);
}
err_free:
kfree(led);
return ret;
}
static int __devexit adp8860_led_remove(struct i2c_client *client)
{
struct adp8860_backlight_platform_data *pdata =
client->dev.platform_data;
struct adp8860_bl *data = i2c_get_clientdata(client);
int i;
for (i = 0; i < pdata->num_leds; i++) {
led_classdev_unregister(&data->led[i].cdev);
cancel_work_sync(&data->led[i].work);
}
kfree(data->led);
return 0;
}
#else
static int __devinit adp8860_led_probe(struct i2c_client *client)
{
return 0;
}
static int __devexit adp8860_led_remove(struct i2c_client *client)
{
return 0;
}
#endif
static int adp8860_bl_set(struct backlight_device *bl, int brightness)
{
struct adp8860_bl *data = bl_get_data(bl);
struct i2c_client *client = data->client;
int ret = 0;
if (data->en_ambl_sens) {
if ((brightness > 0) && (brightness < ADP8860_MAX_BRIGHTNESS)) {
/* Disable Ambient Light auto adjust */
ret |= adp8860_clr_bits(client, ADP8860_MDCR,
CMP_AUTOEN);
ret |= adp8860_write(client, ADP8860_BLMX1, brightness);
} else {
/*
* MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
* restore daylight l1 sysfs brightness
*/
ret |= adp8860_write(client, ADP8860_BLMX1,
data->cached_daylight_max);
ret |= adp8860_set_bits(client, ADP8860_MDCR,
CMP_AUTOEN);
}
} else
ret |= adp8860_write(client, ADP8860_BLMX1, brightness);
if (data->current_brightness && brightness == 0)
ret |= adp8860_set_bits(client,
ADP8860_MDCR, DIM_EN);
else if (data->current_brightness == 0 && brightness)
ret |= adp8860_clr_bits(client,
ADP8860_MDCR, DIM_EN);
if (!ret)
data->current_brightness = brightness;
return ret;
}
static int adp8860_bl_update_status(struct backlight_device *bl)
{
int brightness = bl->props.brightness;
if (bl->props.power != FB_BLANK_UNBLANK)
brightness = 0;
if (bl->props.fb_blank != FB_BLANK_UNBLANK)
brightness = 0;
return adp8860_bl_set(bl, brightness);
}
static int adp8860_bl_get_brightness(struct backlight_device *bl)
{
struct adp8860_bl *data = bl_get_data(bl);
return data->current_brightness;
}
static const struct backlight_ops adp8860_bl_ops = {
.update_status = adp8860_bl_update_status,
.get_brightness = adp8860_bl_get_brightness,
};
static int adp8860_bl_setup(struct backlight_device *bl)
{
struct adp8860_bl *data = bl_get_data(bl);
struct i2c_client *client = data->client;
struct adp8860_backlight_platform_data *pdata = data->pdata;
int ret = 0;
ret |= adp8860_write(client, ADP8860_BLSEN, ~pdata->bl_led_assign);
ret |= adp8860_write(client, ADP8860_BLMX1, pdata->l1_daylight_max);
ret |= adp8860_write(client, ADP8860_BLDM1, pdata->l1_daylight_dim);
if (data->en_ambl_sens) {
data->cached_daylight_max = pdata->l1_daylight_max;
ret |= adp8860_write(client, ADP8860_BLMX2,
pdata->l2_office_max);
ret |= adp8860_write(client, ADP8860_BLDM2,
pdata->l2_office_dim);
ret |= adp8860_write(client, ADP8860_BLMX3,
pdata->l3_dark_max);
ret |= adp8860_write(client, ADP8860_BLDM3,
pdata->l3_dark_dim);
ret |= adp8860_write(client, ADP8860_L2_TRP, pdata->l2_trip);
ret |= adp8860_write(client, ADP8860_L2_HYS, pdata->l2_hyst);
ret |= adp8860_write(client, ADP8860_L3_TRP, pdata->l3_trip);
ret |= adp8860_write(client, ADP8860_L3_HYS, pdata->l3_hyst);
ret |= adp8860_write(client, ADP8860_CCFG, L2_EN | L3_EN |
ALS_CCFG_VAL(pdata->abml_filt));
}
ret |= adp8860_write(client, ADP8860_CFGR,
BL_CFGR_VAL(pdata->bl_fade_law, 0));
ret |= adp8860_write(client, ADP8860_BLFR, FADE_VAL(pdata->bl_fade_in,
pdata->bl_fade_out));
ret |= adp8860_set_bits(client, ADP8860_MDCR, BLEN | DIM_EN | NSTBY |
(data->gdwn_dis ? GDWN_DIS : 0));
return ret;
}
static ssize_t adp8860_show(struct device *dev, char *buf, int reg)
{
struct adp8860_bl *data = dev_get_drvdata(dev);
int error;
uint8_t reg_val;
mutex_lock(&data->lock);
error = adp8860_read(data->client, reg, &reg_val);
mutex_unlock(&data->lock);
if (error < 0)
return error;
return sprintf(buf, "%u\n", reg_val);
}
static ssize_t adp8860_store(struct device *dev, const char *buf,
size_t count, int reg)
{
struct adp8860_bl *data = dev_get_drvdata(dev);
unsigned long val;
int ret;
ret = strict_strtoul(buf, 10, &val);
if (ret)
return ret;
mutex_lock(&data->lock);
adp8860_write(data->client, reg, val);
mutex_unlock(&data->lock);
return count;
}
static ssize_t adp8860_bl_l3_dark_max_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp8860_show(dev, buf, ADP8860_BLMX3);
}
static ssize_t adp8860_bl_l3_dark_max_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
return adp8860_store(dev, buf, count, ADP8860_BLMX3);
}
static DEVICE_ATTR(l3_dark_max, 0664, adp8860_bl_l3_dark_max_show,
adp8860_bl_l3_dark_max_store);
static ssize_t adp8860_bl_l2_office_max_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp8860_show(dev, buf, ADP8860_BLMX2);
}
static ssize_t adp8860_bl_l2_office_max_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
return adp8860_store(dev, buf, count, ADP8860_BLMX2);
}
static DEVICE_ATTR(l2_office_max, 0664, adp8860_bl_l2_office_max_show,
adp8860_bl_l2_office_max_store);
static ssize_t adp8860_bl_l1_daylight_max_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp8860_show(dev, buf, ADP8860_BLMX1);
}
static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct adp8860_bl *data = dev_get_drvdata(dev);
strict_strtoul(buf, 10, &data->cached_daylight_max);
return adp8860_store(dev, buf, count, ADP8860_BLMX1);
}
static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show,
adp8860_bl_l1_daylight_max_store);
static ssize_t adp8860_bl_l3_dark_dim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp8860_show(dev, buf, ADP8860_BLDM3);
}
static ssize_t adp8860_bl_l3_dark_dim_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return adp8860_store(dev, buf, count, ADP8860_BLDM3);
}
static DEVICE_ATTR(l3_dark_dim, 0664, adp8860_bl_l3_dark_dim_show,
adp8860_bl_l3_dark_dim_store);
static ssize_t adp8860_bl_l2_office_dim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp8860_show(dev, buf, ADP8860_BLDM2);
}
static ssize_t adp8860_bl_l2_office_dim_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return adp8860_store(dev, buf, count, ADP8860_BLDM2);
}
static DEVICE_ATTR(l2_office_dim, 0664, adp8860_bl_l2_office_dim_show,
adp8860_bl_l2_office_dim_store);
static ssize_t adp8860_bl_l1_daylight_dim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp8860_show(dev, buf, ADP8860_BLDM1);
}
static ssize_t adp8860_bl_l1_daylight_dim_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return adp8860_store(dev, buf, count, ADP8860_BLDM1);
}
static DEVICE_ATTR(l1_daylight_dim, 0664, adp8860_bl_l1_daylight_dim_show,
adp8860_bl_l1_daylight_dim_store);
#ifdef ADP8860_EXT_FEATURES
static ssize_t adp8860_bl_ambient_light_level_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adp8860_bl *data = dev_get_drvdata(dev);
int error;
uint8_t reg_val;
uint16_t ret_val;
mutex_lock(&data->lock);
error = adp8860_read(data->client, ADP8860_PH1LEVL, &reg_val);
ret_val = reg_val;
error |= adp8860_read(data->client, ADP8860_PH1LEVH, &reg_val);
mutex_unlock(&data->lock);
if (error < 0)
return error;
/* Return 13-bit conversion value for the first light sensor */
ret_val += (reg_val & 0x1F) << 8;
return sprintf(buf, "%u\n", ret_val);
}
static DEVICE_ATTR(ambient_light_level, 0444,
adp8860_bl_ambient_light_level_show, NULL);
static ssize_t adp8860_bl_ambient_light_zone_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adp8860_bl *data = dev_get_drvdata(dev);
int error;
uint8_t reg_val;
mutex_lock(&data->lock);
error = adp8860_read(data->client, ADP8860_CFGR, &reg_val);
mutex_unlock(&data->lock);
if (error < 0)
return error;
return sprintf(buf, "%u\n",
((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1);
}
static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct adp8860_bl *data = dev_get_drvdata(dev);
unsigned long val;
uint8_t reg_val;
int ret;
ret = strict_strtoul(buf, 10, &val);
if (ret)
return ret;
if (val == 0) {
/* Enable automatic ambient light sensing */
adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
} else if ((val > 0) && (val < 6)) {
/* Disable automatic ambient light sensing */
adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
/* Set user supplied ambient light zone */
mutex_lock(&data->lock);
adp8860_read(data->client, ADP8860_CFGR, &reg_val);
reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
reg_val |= val << CFGR_BLV_SHIFT;
adp8860_write(data->client, ADP8860_CFGR, reg_val);
mutex_unlock(&data->lock);
}
return count;
}
static DEVICE_ATTR(ambient_light_zone, 0664,
adp8860_bl_ambient_light_zone_show,
adp8860_bl_ambient_light_zone_store);
#endif
static struct attribute *adp8860_bl_attributes[] = {
&dev_attr_l3_dark_max.attr,
&dev_attr_l3_dark_dim.attr,
&dev_attr_l2_office_max.attr,
&dev_attr_l2_office_dim.attr,
&dev_attr_l1_daylight_max.attr,
&dev_attr_l1_daylight_dim.attr,
#ifdef ADP8860_EXT_FEATURES
&dev_attr_ambient_light_level.attr,
&dev_attr_ambient_light_zone.attr,
#endif
NULL
};
static const struct attribute_group adp8860_bl_attr_group = {
.attrs = adp8860_bl_attributes,
};
static int __devinit adp8860_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct backlight_device *bl;
struct adp8860_bl *data;
struct adp8860_backlight_platform_data *pdata =
client->dev.platform_data;
struct backlight_properties props;
uint8_t reg_val;
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
return -EIO;
}
if (!pdata) {
dev_err(&client->dev, "no platform data?\n");
return -EINVAL;
}
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
ret = adp8860_read(client, ADP8860_MFDVID, &reg_val);
if (ret < 0)
goto out2;
switch (ADP8860_MANID(reg_val)) {
case ADP8863_MANUFID:
data->gdwn_dis = !!pdata->gdwn_dis;
case ADP8860_MANUFID:
data->en_ambl_sens = !!pdata->en_ambl_sens;
break;
case ADP8861_MANUFID:
data->gdwn_dis = !!pdata->gdwn_dis;
break;
default:
dev_err(&client->dev, "failed to probe\n");
ret = -ENODEV;
goto out2;
}
/* It's confirmed that the DEVID field is actually a REVID */
data->revid = ADP8860_DEVID(reg_val);
data->client = client;
data->pdata = pdata;
data->id = id->driver_data;
data->current_brightness = 0;
i2c_set_clientdata(client, data);
memset(&props, 0, sizeof(props));
props.max_brightness = ADP8860_MAX_BRIGHTNESS;
mutex_init(&data->lock);
bl = backlight_device_register(dev_driver_string(&client->dev),
&client->dev, data, &adp8860_bl_ops, &props);
if (IS_ERR(bl)) {
dev_err(&client->dev, "failed to register backlight\n");
ret = PTR_ERR(bl);
goto out2;
}
bl->props.max_brightness =
bl->props.brightness = ADP8860_MAX_BRIGHTNESS;
data->bl = bl;
if (data->en_ambl_sens)
ret = sysfs_create_group(&bl->dev.kobj,
&adp8860_bl_attr_group);
if (ret) {
dev_err(&client->dev, "failed to register sysfs\n");
goto out1;
}
ret = adp8860_bl_setup(bl);
if (ret) {
ret = -EIO;
goto out;
}
backlight_update_status(bl);
dev_info(&client->dev, "%s Rev.%d Backlight\n",
client->name, data->revid);
if (pdata->num_leds)
adp8860_led_probe(client);
return 0;
out:
if (data->en_ambl_sens)
sysfs_remove_group(&data->bl->dev.kobj,
&adp8860_bl_attr_group);
out1:
backlight_device_unregister(bl);
out2:
i2c_set_clientdata(client, NULL);
kfree(data);
return ret;
}
static int __devexit adp8860_remove(struct i2c_client *client)
{
struct adp8860_bl *data = i2c_get_clientdata(client);
adp8860_clr_bits(client, ADP8860_MDCR, NSTBY);
if (data->led)
adp8860_led_remove(client);
if (data->en_ambl_sens)
sysfs_remove_group(&data->bl->dev.kobj,
&adp8860_bl_attr_group);
backlight_device_unregister(data->bl);
i2c_set_clientdata(client, NULL);
kfree(data);
return 0;
}
#ifdef CONFIG_PM
static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message)
{
adp8860_clr_bits(client, ADP8860_MDCR, NSTBY);
return 0;
}
static int adp8860_i2c_resume(struct i2c_client *client)
{
adp8860_set_bits(client, ADP8860_MDCR, NSTBY);
return 0;
}
#else
#define adp8860_i2c_suspend NULL
#define adp8860_i2c_resume NULL
#endif
static const struct i2c_device_id adp8860_id[] = {
{ "adp8860", adp8860 },
{ "adp8861", adp8861 },
{ "adp8863", adp8863 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adp8860_id);
static struct i2c_driver adp8860_driver = {
.driver = {
.name = KBUILD_MODNAME,
},
.probe = adp8860_probe,
.remove = __devexit_p(adp8860_remove),
.suspend = adp8860_i2c_suspend,
.resume = adp8860_i2c_resume,
.id_table = adp8860_id,
};
static int __init adp8860_init(void)
{
return i2c_add_driver(&adp8860_driver);
}
module_init(adp8860_init);
static void __exit adp8860_exit(void)
{
i2c_del_driver(&adp8860_driver);
}
module_exit(adp8860_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADP8860 Backlight driver");
MODULE_ALIAS("i2c:adp8860-backlight");
...@@ -107,8 +107,8 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev) ...@@ -107,8 +107,8 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev)
props.max_brightness = 0xff; props.max_brightness = 0xff;
bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,
bl, &adx_backlight_ops, &props); bl, &adx_backlight_ops, &props);
if (!bldev) { if (IS_ERR(bldev)) {
ret = -ENOMEM; ret = PTR_ERR(bldev);
goto out; goto out;
} }
......
/*
* Driver for the Cirrus EP93xx lcd backlight
*
* Copyright (c) 2010 H Hartley Sweeten <hsweeten@visionengravers.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This driver controls the pulse width modulated brightness control output,
* BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors.
*/
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <mach/hardware.h>
#define EP93XX_RASTER_REG(x) (EP93XX_RASTER_BASE + (x))
#define EP93XX_RASTER_BRIGHTNESS EP93XX_RASTER_REG(0x20)
#define EP93XX_MAX_COUNT 255
#define EP93XX_MAX_BRIGHT 255
#define EP93XX_DEF_BRIGHT 128
struct ep93xxbl {
void __iomem *mmio;
int brightness;
};
static int ep93xxbl_set(struct backlight_device *bl, int brightness)
{
struct ep93xxbl *ep93xxbl = bl_get_data(bl);
__raw_writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio);
ep93xxbl->brightness = brightness;
return 0;
}
static int ep93xxbl_update_status(struct backlight_device *bl)
{
int brightness = bl->props.brightness;
if (bl->props.power != FB_BLANK_UNBLANK ||
bl->props.fb_blank != FB_BLANK_UNBLANK)
brightness = 0;
return ep93xxbl_set(bl, brightness);
}
static int ep93xxbl_get_brightness(struct backlight_device *bl)
{
struct ep93xxbl *ep93xxbl = bl_get_data(bl);
return ep93xxbl->brightness;
}
static const struct backlight_ops ep93xxbl_ops = {
.update_status = ep93xxbl_update_status,
.get_brightness = ep93xxbl_get_brightness,
};
static int __init ep93xxbl_probe(struct platform_device *dev)
{
struct ep93xxbl *ep93xxbl;
struct backlight_device *bl;
struct backlight_properties props;
ep93xxbl = devm_kzalloc(&dev->dev, sizeof(*ep93xxbl), GFP_KERNEL);
if (!ep93xxbl)
return -ENOMEM;
/*
* This register is located in the range already ioremap'ed by
* the framebuffer driver. A MFD driver seems a bit of overkill
* to handle this so use the static I/O mapping; this address
* is already virtual.
*
* NOTE: No locking is required; the framebuffer does not touch
* this register.
*/
ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS;
memset(&props, 0, sizeof(struct backlight_properties));
props.max_brightness = EP93XX_MAX_BRIGHT;
bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl,
&ep93xxbl_ops, &props);
if (IS_ERR(bl))
return PTR_ERR(bl);
bl->props.brightness = EP93XX_DEF_BRIGHT;
platform_set_drvdata(dev, bl);
ep93xxbl_update_status(bl);
return 0;
}
static int ep93xxbl_remove(struct platform_device *dev)
{
struct backlight_device *bl = platform_get_drvdata(dev);
backlight_device_unregister(bl);
platform_set_drvdata(dev, NULL);
return 0;
}
#ifdef CONFIG_PM
static int ep93xxbl_suspend(struct platform_device *dev, pm_message_t state)
{
struct backlight_device *bl = platform_get_drvdata(dev);
return ep93xxbl_set(bl, 0);
}
static int ep93xxbl_resume(struct platform_device *dev)
{
struct backlight_device *bl = platform_get_drvdata(dev);
backlight_update_status(bl);
return 0;
}
#else
#define ep93xxbl_suspend NULL
#define ep93xxbl_resume NULL
#endif
static struct platform_driver ep93xxbl_driver = {
.driver = {
.name = "ep93xx-bl",
.owner = THIS_MODULE,
},
.probe = ep93xxbl_probe,
.remove = __devexit_p(ep93xxbl_remove),
.suspend = ep93xxbl_suspend,
.resume = ep93xxbl_resume,
};
static int __init ep93xxbl_init(void)
{
return platform_driver_register(&ep93xxbl_driver);
}
module_init(ep93xxbl_init);
static void __exit ep93xxbl_exit(void)
{
platform_driver_unregister(&ep93xxbl_driver);
}
module_exit(ep93xxbl_exit);
MODULE_DESCRIPTION("EP93xx Backlight Driver");
MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ep93xx-bl");
...@@ -125,8 +125,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) ...@@ -125,8 +125,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
if (priv == NULL) { if (priv == NULL) {
dev_err(&spi->dev, "No memory for this device.\n"); dev_err(&spi->dev, "No memory for this device.\n");
ret = -ENOMEM; return -ENOMEM;
goto err;
} }
dev_set_drvdata(&spi->dev, priv); dev_set_drvdata(&spi->dev, priv);
...@@ -139,7 +138,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) ...@@ -139,7 +138,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
if (ret) { if (ret) {
dev_err(&spi->dev, dev_err(&spi->dev,
"Unable to get the lcd l4f00242t03 reset gpio.\n"); "Unable to get the lcd l4f00242t03 reset gpio.\n");
return ret; goto err;
} }
ret = gpio_direction_output(pdata->reset_gpio, 1); ret = gpio_direction_output(pdata->reset_gpio, 1);
...@@ -151,7 +150,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) ...@@ -151,7 +150,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
if (ret) { if (ret) {
dev_err(&spi->dev, dev_err(&spi->dev,
"Unable to get the lcd l4f00242t03 data en gpio.\n"); "Unable to get the lcd l4f00242t03 data en gpio.\n");
return ret; goto err2;
} }
ret = gpio_direction_output(pdata->data_enable_gpio, 0); ret = gpio_direction_output(pdata->data_enable_gpio, 0);
...@@ -222,9 +221,9 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi) ...@@ -222,9 +221,9 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi)
gpio_free(pdata->reset_gpio); gpio_free(pdata->reset_gpio);
if (priv->io_reg) if (priv->io_reg)
regulator_put(priv->core_reg);
if (priv->core_reg)
regulator_put(priv->io_reg); regulator_put(priv->io_reg);
if (priv->core_reg)
regulator_put(priv->core_reg);
kfree(priv); kfree(priv);
......
...@@ -162,6 +162,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) ...@@ -162,6 +162,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
backlight_update_status(bl); backlight_update_status(bl);
return 0; return 0;
out: out:
backlight_device_unregister(bl);
kfree(data); kfree(data);
return ret; return ret;
} }
......
...@@ -141,7 +141,7 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { ...@@ -141,7 +141,7 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
.callback = mbp_dmi_match, .callback = mbp_dmi_match,
.ident = "MacBook 1,1", .ident = "MacBook 1,1",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
}, },
.driver_data = (void *)&intel_chipset_data, .driver_data = (void *)&intel_chipset_data,
...@@ -182,6 +182,42 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { ...@@ -182,6 +182,42 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
}, },
.driver_data = (void *)&intel_chipset_data, .driver_data = (void *)&intel_chipset_data,
}, },
{
.callback = mbp_dmi_match,
.ident = "MacBookPro 1,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookPro 1,2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,2"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookPro 2,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,1"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookPro 2,2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
},
.driver_data = (void *)&intel_chipset_data,
},
{ {
.callback = mbp_dmi_match, .callback = mbp_dmi_match,
.ident = "MacBookPro 3,1", .ident = "MacBookPro 3,1",
...@@ -236,6 +272,15 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { ...@@ -236,6 +272,15 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
}, },
.driver_data = (void *)&nvidia_chipset_data, .driver_data = (void *)&nvidia_chipset_data,
}, },
{
.callback = mbp_dmi_match,
.ident = "MacBook 6,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"),
},
.driver_data = (void *)&nvidia_chipset_data,
},
{ {
.callback = mbp_dmi_match, .callback = mbp_dmi_match,
.ident = "MacBookAir 2,1", .ident = "MacBookAir 2,1",
......
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
* PCF50633 backlight device driver
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/mfd/pcf50633/core.h>
#include <linux/mfd/pcf50633/backlight.h>
struct pcf50633_bl {
struct pcf50633 *pcf;
struct backlight_device *bl;
unsigned int brightness;
unsigned int brightness_limit;
};
/*
* pcf50633_bl_set_brightness_limit
*
* Update the brightness limit for the pc50633 backlight. The actual brightness
* will not go above the limit. This is useful to limit power drain for example
* on low battery.
*
* @dev: Pointer to a pcf50633 device
* @limit: The brightness limit. Valid values are 0-63
*/
int pcf50633_bl_set_brightness_limit(struct pcf50633 *pcf, unsigned int limit)
{
struct pcf50633_bl *pcf_bl = platform_get_drvdata(pcf->bl_pdev);
if (!pcf_bl)
return -ENODEV;
pcf_bl->brightness_limit = limit & 0x3f;
backlight_update_status(pcf_bl->bl);
return 0;
}
static int pcf50633_bl_update_status(struct backlight_device *bl)
{
struct pcf50633_bl *pcf_bl = bl_get_data(bl);
unsigned int new_brightness;
if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK) ||
bl->props.power != FB_BLANK_UNBLANK)
new_brightness = 0;
else if (bl->props.brightness < pcf_bl->brightness_limit)
new_brightness = bl->props.brightness;
else
new_brightness = pcf_bl->brightness_limit;
if (pcf_bl->brightness == new_brightness)
return 0;
if (new_brightness) {
pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDOUT,
new_brightness);
if (!pcf_bl->brightness)
pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 1);
} else {
pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 0);
}
pcf_bl->brightness = new_brightness;
return 0;
}
static int pcf50633_bl_get_brightness(struct backlight_device *bl)
{
struct pcf50633_bl *pcf_bl = bl_get_data(bl);
return pcf_bl->brightness;
}
static const struct backlight_ops pcf50633_bl_ops = {
.get_brightness = pcf50633_bl_get_brightness,
.update_status = pcf50633_bl_update_status,
.options = BL_CORE_SUSPENDRESUME,
};
static int __devinit pcf50633_bl_probe(struct platform_device *pdev)
{
int ret;
struct pcf50633_bl *pcf_bl;
struct device *parent = pdev->dev.parent;
struct pcf50633_platform_data *pcf50633_data = parent->platform_data;
struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data;
struct backlight_properties bl_props;
pcf_bl = kzalloc(sizeof(*pcf_bl), GFP_KERNEL);
if (!pcf_bl)
return -ENOMEM;
bl_props.max_brightness = 0x3f;
bl_props.power = FB_BLANK_UNBLANK;
if (pdata) {
bl_props.brightness = pdata->default_brightness;
pcf_bl->brightness_limit = pdata->default_brightness_limit;
} else {
bl_props.brightness = 0x3f;
pcf_bl->brightness_limit = 0x3f;
}
pcf_bl->pcf = dev_to_pcf50633(pdev->dev.parent);
pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl,
&pcf50633_bl_ops, &bl_props);
if (IS_ERR(pcf_bl->bl)) {
ret = PTR_ERR(pcf_bl->bl);
goto err_free;
}
platform_set_drvdata(pdev, pcf_bl);
pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDDIM, pdata->ramp_time);
/* Should be different from bl_props.brightness, so we do not exit
* update_status early the first time it's called */
pcf_bl->brightness = pcf_bl->bl->props.brightness + 1;
backlight_update_status(pcf_bl->bl);
return 0;
err_free:
kfree(pcf_bl);
return ret;
}
static int __devexit pcf50633_bl_remove(struct platform_device *pdev)
{
struct pcf50633_bl *pcf_bl = platform_get_drvdata(pdev);
backlight_device_unregister(pcf_bl->bl);
platform_set_drvdata(pdev, NULL);
kfree(pcf_bl);
return 0;
}
static struct platform_driver pcf50633_bl_driver = {
.probe = pcf50633_bl_probe,
.remove = __devexit_p(pcf50633_bl_remove),
.driver = {
.name = "pcf50633-backlight",
},
};
static int __init pcf50633_bl_init(void)
{
return platform_driver_register(&pcf50633_bl_driver);
}
module_init(pcf50633_bl_init);
static void __exit pcf50633_bl_exit(void)
{
platform_driver_unregister(&pcf50633_bl_driver);
}
module_exit(pcf50633_bl_exit);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("PCF50633 backlight driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pcf50633-backlight");
/*
* S6E63M0 AMOLED LCD panel driver.
*
* Author: InKi Dae <inki.dae@samsung.com>
*
* Derived from drivers/video/omap/lcd-apollon.c
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/wait.h>
#include <linux/fb.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/lcd.h>
#include <linux/backlight.h>
#include "s6e63m0_gamma.h"
#define SLEEPMSEC 0x1000
#define ENDDEF 0x2000
#define DEFMASK 0xFF00
#define COMMAND_ONLY 0xFE
#define DATA_ONLY 0xFF
#define MIN_BRIGHTNESS 0
#define MAX_BRIGHTNESS 10
#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
struct s6e63m0 {
struct device *dev;
struct spi_device *spi;
unsigned int power;
unsigned int current_brightness;
unsigned int gamma_mode;
unsigned int gamma_table_count;
struct lcd_device *ld;
struct backlight_device *bd;
struct lcd_platform_data *lcd_pd;
};
static const unsigned short SEQ_PANEL_CONDITION_SET[] = {
0xF8, 0x01,
DATA_ONLY, 0x27,
DATA_ONLY, 0x27,
DATA_ONLY, 0x07,
DATA_ONLY, 0x07,
DATA_ONLY, 0x54,
DATA_ONLY, 0x9f,
DATA_ONLY, 0x63,
DATA_ONLY, 0x86,
DATA_ONLY, 0x1a,
DATA_ONLY, 0x33,
DATA_ONLY, 0x0d,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
ENDDEF, 0x0000
};
static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = {
0xf2, 0x02,
DATA_ONLY, 0x03,
DATA_ONLY, 0x1c,
DATA_ONLY, 0x10,
DATA_ONLY, 0x10,
0xf7, 0x03,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
ENDDEF, 0x0000
};
static const unsigned short SEQ_GAMMA_SETTING[] = {
0xfa, 0x00,
DATA_ONLY, 0x18,
DATA_ONLY, 0x08,
DATA_ONLY, 0x24,
DATA_ONLY, 0x64,
DATA_ONLY, 0x56,
DATA_ONLY, 0x33,
DATA_ONLY, 0xb6,
DATA_ONLY, 0xba,
DATA_ONLY, 0xa8,
DATA_ONLY, 0xac,
DATA_ONLY, 0xb1,
DATA_ONLY, 0x9d,
DATA_ONLY, 0xc1,
DATA_ONLY, 0xc1,
DATA_ONLY, 0xb7,
DATA_ONLY, 0x00,
DATA_ONLY, 0x9c,
DATA_ONLY, 0x00,
DATA_ONLY, 0x9f,
DATA_ONLY, 0x00,
DATA_ONLY, 0xd6,
0xfa, 0x01,
ENDDEF, 0x0000
};
static const unsigned short SEQ_ETC_CONDITION_SET[] = {
0xf6, 0x00,
DATA_ONLY, 0x8c,
DATA_ONLY, 0x07,
0xb3, 0xc,
0xb5, 0x2c,
DATA_ONLY, 0x12,
DATA_ONLY, 0x0c,
DATA_ONLY, 0x0a,
DATA_ONLY, 0x10,
DATA_ONLY, 0x0e,
DATA_ONLY, 0x17,
DATA_ONLY, 0x13,
DATA_ONLY, 0x1f,
DATA_ONLY, 0x1a,
DATA_ONLY, 0x2a,
DATA_ONLY, 0x24,
DATA_ONLY, 0x1f,
DATA_ONLY, 0x1b,
DATA_ONLY, 0x1a,
DATA_ONLY, 0x17,
DATA_ONLY, 0x2b,
DATA_ONLY, 0x26,
DATA_ONLY, 0x22,
DATA_ONLY, 0x20,
DATA_ONLY, 0x3a,
DATA_ONLY, 0x34,
DATA_ONLY, 0x30,
DATA_ONLY, 0x2c,
DATA_ONLY, 0x29,
DATA_ONLY, 0x26,
DATA_ONLY, 0x25,
DATA_ONLY, 0x23,
DATA_ONLY, 0x21,
DATA_ONLY, 0x20,
DATA_ONLY, 0x1e,
DATA_ONLY, 0x1e,
0xb6, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x11,
DATA_ONLY, 0x22,
DATA_ONLY, 0x33,
DATA_ONLY, 0x44,
DATA_ONLY, 0x44,
DATA_ONLY, 0x44,
DATA_ONLY, 0x55,
DATA_ONLY, 0x55,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
0xb7, 0x2c,
DATA_ONLY, 0x12,
DATA_ONLY, 0x0c,
DATA_ONLY, 0x0a,
DATA_ONLY, 0x10,
DATA_ONLY, 0x0e,
DATA_ONLY, 0x17,
DATA_ONLY, 0x13,
DATA_ONLY, 0x1f,
DATA_ONLY, 0x1a,
DATA_ONLY, 0x2a,
DATA_ONLY, 0x24,
DATA_ONLY, 0x1f,
DATA_ONLY, 0x1b,
DATA_ONLY, 0x1a,
DATA_ONLY, 0x17,
DATA_ONLY, 0x2b,
DATA_ONLY, 0x26,
DATA_ONLY, 0x22,
DATA_ONLY, 0x20,
DATA_ONLY, 0x3a,
DATA_ONLY, 0x34,
DATA_ONLY, 0x30,
DATA_ONLY, 0x2c,
DATA_ONLY, 0x29,
DATA_ONLY, 0x26,
DATA_ONLY, 0x25,
DATA_ONLY, 0x23,
DATA_ONLY, 0x21,
DATA_ONLY, 0x20,
DATA_ONLY, 0x1e,
DATA_ONLY, 0x1e,
0xb8, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x11,
DATA_ONLY, 0x22,
DATA_ONLY, 0x33,
DATA_ONLY, 0x44,
DATA_ONLY, 0x44,
DATA_ONLY, 0x44,
DATA_ONLY, 0x55,
DATA_ONLY, 0x55,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
0xb9, 0x2c,
DATA_ONLY, 0x12,
DATA_ONLY, 0x0c,
DATA_ONLY, 0x0a,
DATA_ONLY, 0x10,
DATA_ONLY, 0x0e,
DATA_ONLY, 0x17,
DATA_ONLY, 0x13,
DATA_ONLY, 0x1f,
DATA_ONLY, 0x1a,
DATA_ONLY, 0x2a,
DATA_ONLY, 0x24,
DATA_ONLY, 0x1f,
DATA_ONLY, 0x1b,
DATA_ONLY, 0x1a,
DATA_ONLY, 0x17,
DATA_ONLY, 0x2b,
DATA_ONLY, 0x26,
DATA_ONLY, 0x22,
DATA_ONLY, 0x20,
DATA_ONLY, 0x3a,
DATA_ONLY, 0x34,
DATA_ONLY, 0x30,
DATA_ONLY, 0x2c,
DATA_ONLY, 0x29,
DATA_ONLY, 0x26,
DATA_ONLY, 0x25,
DATA_ONLY, 0x23,
DATA_ONLY, 0x21,
DATA_ONLY, 0x20,
DATA_ONLY, 0x1e,
DATA_ONLY, 0x1e,
0xba, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x11,
DATA_ONLY, 0x22,
DATA_ONLY, 0x33,
DATA_ONLY, 0x44,
DATA_ONLY, 0x44,
DATA_ONLY, 0x44,
DATA_ONLY, 0x55,
DATA_ONLY, 0x55,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
DATA_ONLY, 0x66,
0xc1, 0x4d,
DATA_ONLY, 0x96,
DATA_ONLY, 0x1d,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x01,
DATA_ONLY, 0xdf,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x03,
DATA_ONLY, 0x1f,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x00,
DATA_ONLY, 0x03,
DATA_ONLY, 0x06,
DATA_ONLY, 0x09,
DATA_ONLY, 0x0d,
DATA_ONLY, 0x0f,
DATA_ONLY, 0x12,
DATA_ONLY, 0x15,
DATA_ONLY, 0x18,
0xb2, 0x10,
DATA_ONLY, 0x10,
DATA_ONLY, 0x0b,
DATA_ONLY, 0x05,
ENDDEF, 0x0000
};
static const unsigned short SEQ_ACL_ON[] = {
/* ACL on */
0xc0, 0x01,
ENDDEF, 0x0000
};
static const unsigned short SEQ_ACL_OFF[] = {
/* ACL off */
0xc0, 0x00,
ENDDEF, 0x0000
};
static const unsigned short SEQ_ELVSS_ON[] = {
/* ELVSS on */
0xb1, 0x0b,
ENDDEF, 0x0000
};
static const unsigned short SEQ_ELVSS_OFF[] = {
/* ELVSS off */
0xb1, 0x0a,
ENDDEF, 0x0000
};
static const unsigned short SEQ_STAND_BY_OFF[] = {
0x11, COMMAND_ONLY,
ENDDEF, 0x0000
};
static const unsigned short SEQ_STAND_BY_ON[] = {
0x10, COMMAND_ONLY,
ENDDEF, 0x0000
};
static const unsigned short SEQ_DISPLAY_ON[] = {
0x29, COMMAND_ONLY,
ENDDEF, 0x0000
};
static int s6e63m0_spi_write_byte(struct s6e63m0 *lcd, int addr, int data)
{
u16 buf[1];
struct spi_message msg;
struct spi_transfer xfer = {
.len = 2,
.tx_buf = buf,
};
buf[0] = (addr << 8) | data;
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
return spi_sync(lcd->spi, &msg);
}
static int s6e63m0_spi_write(struct s6e63m0 *lcd, unsigned char address,
unsigned char command)
{
int ret = 0;
if (address != DATA_ONLY)
ret = s6e63m0_spi_write_byte(lcd, 0x0, address);
if (command != COMMAND_ONLY)
ret = s6e63m0_spi_write_byte(lcd, 0x1, command);
return ret;
}
static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd,
const unsigned short *wbuf)
{
int ret = 0, i = 0;
while ((wbuf[i] & DEFMASK) != ENDDEF) {
if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]);
if (ret)
break;
} else
udelay(wbuf[i+1]*1000);
i += 2;
}
return ret;
}
static int _s6e63m0_gamma_ctl(struct s6e63m0 *lcd, const unsigned int *gamma)
{
unsigned int i = 0;
int ret = 0;
/* disable gamma table updating. */
ret = s6e63m0_spi_write(lcd, 0xfa, 0x00);
if (ret) {
dev_err(lcd->dev, "failed to disable gamma table updating.\n");
goto gamma_err;
}
for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) {
ret = s6e63m0_spi_write(lcd, DATA_ONLY, gamma[i]);
if (ret) {
dev_err(lcd->dev, "failed to set gamma table.\n");
goto gamma_err;
}
}
/* update gamma table. */
ret = s6e63m0_spi_write(lcd, 0xfa, 0x01);
if (ret)
dev_err(lcd->dev, "failed to update gamma table.\n");
gamma_err:
return ret;
}
static int s6e63m0_gamma_ctl(struct s6e63m0 *lcd, int gamma)
{
int ret = 0;
ret = _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
return ret;
}
static int s6e63m0_ldi_init(struct s6e63m0 *lcd)
{
int ret, i;
const unsigned short *init_seq[] = {
SEQ_PANEL_CONDITION_SET,
SEQ_DISPLAY_CONDITION_SET,
SEQ_GAMMA_SETTING,
SEQ_ETC_CONDITION_SET,
SEQ_ACL_ON,
SEQ_ELVSS_ON,
};
for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
ret = s6e63m0_panel_send_sequence(lcd, init_seq[i]);
if (ret)
break;
}
return ret;
}
static int s6e63m0_ldi_enable(struct s6e63m0 *lcd)
{
int ret = 0, i;
const unsigned short *enable_seq[] = {
SEQ_STAND_BY_OFF,
SEQ_DISPLAY_ON,
};
for (i = 0; i < ARRAY_SIZE(enable_seq); i++) {
ret = s6e63m0_panel_send_sequence(lcd, enable_seq[i]);
if (ret)
break;
}
return ret;
}
static int s6e63m0_ldi_disable(struct s6e63m0 *lcd)
{
int ret;
ret = s6e63m0_panel_send_sequence(lcd, SEQ_STAND_BY_ON);
return ret;
}
static int s6e63m0_power_on(struct s6e63m0 *lcd)
{
int ret = 0;
struct lcd_platform_data *pd = NULL;
struct backlight_device *bd = NULL;
pd = lcd->lcd_pd;
if (!pd) {
dev_err(lcd->dev, "platform data is NULL.\n");
return -EFAULT;
}
bd = lcd->bd;
if (!bd) {
dev_err(lcd->dev, "backlight device is NULL.\n");
return -EFAULT;
}
if (!pd->power_on) {
dev_err(lcd->dev, "power_on is NULL.\n");
return -EFAULT;
} else {
pd->power_on(lcd->ld, 1);
mdelay(pd->power_on_delay);
}
if (!pd->reset) {
dev_err(lcd->dev, "reset is NULL.\n");
return -EFAULT;
} else {
pd->reset(lcd->ld);
mdelay(pd->reset_delay);
}
ret = s6e63m0_ldi_init(lcd);
if (ret) {
dev_err(lcd->dev, "failed to initialize ldi.\n");
return ret;
}
ret = s6e63m0_ldi_enable(lcd);
if (ret) {
dev_err(lcd->dev, "failed to enable ldi.\n");
return ret;
}
/* set brightness to current value after power on or resume. */
ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness);
if (ret) {
dev_err(lcd->dev, "lcd gamma setting failed.\n");
return ret;
}
return 0;
}
static int s6e63m0_power_off(struct s6e63m0 *lcd)
{
int ret = 0;
struct lcd_platform_data *pd = NULL;
pd = lcd->lcd_pd;
if (!pd) {
dev_err(lcd->dev, "platform data is NULL.\n");
return -EFAULT;
}
ret = s6e63m0_ldi_disable(lcd);
if (ret) {
dev_err(lcd->dev, "lcd setting failed.\n");
return -EIO;
}
mdelay(pd->power_off_delay);
if (!pd->power_on) {
dev_err(lcd->dev, "power_on is NULL.\n");
return -EFAULT;
} else
pd->power_on(lcd->ld, 0);
return 0;
}
static int s6e63m0_power(struct s6e63m0 *lcd, int power)
{
int ret = 0;
if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
ret = s6e63m0_power_on(lcd);
else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
ret = s6e63m0_power_off(lcd);
if (!ret)
lcd->power = power;
return ret;
}
static int s6e63m0_set_power(struct lcd_device *ld, int power)
{
struct s6e63m0 *lcd = lcd_get_data(ld);
if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
power != FB_BLANK_NORMAL) {
dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
return -EINVAL;
}
return s6e63m0_power(lcd, power);
}
static int s6e63m0_get_power(struct lcd_device *ld)
{
struct s6e63m0 *lcd = lcd_get_data(ld);
return lcd->power;
}
static int s6e63m0_get_brightness(struct backlight_device *bd)
{
return bd->props.brightness;
}
static int s6e63m0_set_brightness(struct backlight_device *bd)
{
int ret = 0, brightness = bd->props.brightness;
struct s6e63m0 *lcd = bl_get_data(bd);
if (brightness < MIN_BRIGHTNESS ||
brightness > bd->props.max_brightness) {
dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
MIN_BRIGHTNESS, MAX_BRIGHTNESS);
return -EINVAL;
}
ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness);
if (ret) {
dev_err(&bd->dev, "lcd brightness setting failed.\n");
return -EIO;
}
return ret;
}
static struct lcd_ops s6e63m0_lcd_ops = {
.set_power = s6e63m0_set_power,
.get_power = s6e63m0_get_power,
};
static const struct backlight_ops s6e63m0_backlight_ops = {
.get_brightness = s6e63m0_get_brightness,
.update_status = s6e63m0_set_brightness,
};
static ssize_t s6e63m0_sysfs_show_gamma_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct s6e63m0 *lcd = dev_get_drvdata(dev);
char temp[10];
switch (lcd->gamma_mode) {
case 0:
sprintf(temp, "2.2 mode\n");
strcat(buf, temp);
break;
case 1:
sprintf(temp, "1.9 mode\n");
strcat(buf, temp);
break;
case 2:
sprintf(temp, "1.7 mode\n");
strcat(buf, temp);
break;
default:
dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7)n");
break;
}
return strlen(buf);
}
static ssize_t s6e63m0_sysfs_store_gamma_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct s6e63m0 *lcd = dev_get_drvdata(dev);
struct backlight_device *bd = NULL;
int brightness, rc;
rc = strict_strtoul(buf, 0, (unsigned long *)&lcd->gamma_mode);
if (rc < 0)
return rc;
bd = lcd->bd;
brightness = bd->props.brightness;
switch (lcd->gamma_mode) {
case 0:
_s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]);
break;
case 1:
_s6e63m0_gamma_ctl(lcd, gamma_table.gamma_19_table[brightness]);
break;
case 2:
_s6e63m0_gamma_ctl(lcd, gamma_table.gamma_17_table[brightness]);
break;
default:
dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7\n");
_s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]);
break;
}
return len;
}
static DEVICE_ATTR(gamma_mode, 0644,
s6e63m0_sysfs_show_gamma_mode, s6e63m0_sysfs_store_gamma_mode);
static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct s6e63m0 *lcd = dev_get_drvdata(dev);
char temp[3];
sprintf(temp, "%d\n", lcd->gamma_table_count);
strcpy(buf, temp);
return strlen(buf);
}
static DEVICE_ATTR(gamma_table, 0644,
s6e63m0_sysfs_show_gamma_table, NULL);
static int __init s6e63m0_probe(struct spi_device *spi)
{
int ret = 0;
struct s6e63m0 *lcd = NULL;
struct lcd_device *ld = NULL;
struct backlight_device *bd = NULL;
lcd = kzalloc(sizeof(struct s6e63m0), GFP_KERNEL);
if (!lcd)
return -ENOMEM;
/* s6e63m0 lcd panel uses 3-wire 9bits SPI Mode. */
spi->bits_per_word = 9;
ret = spi_setup(spi);
if (ret < 0) {
dev_err(&spi->dev, "spi setup failed.\n");
goto out_free_lcd;
}
lcd->spi = spi;
lcd->dev = &spi->dev;
lcd->lcd_pd = (struct lcd_platform_data *)spi->dev.platform_data;
if (!lcd->lcd_pd) {
dev_err(&spi->dev, "platform data is NULL.\n");
goto out_free_lcd;
}
ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops);
if (IS_ERR(ld)) {
ret = PTR_ERR(ld);
goto out_free_lcd;
}
lcd->ld = ld;
bd = backlight_device_register("s6e63m0bl-bl", &spi->dev, lcd,
&s6e63m0_backlight_ops, NULL);
if (IS_ERR(bd)) {
ret = PTR_ERR(bd);
goto out_lcd_unregister;
}
bd->props.max_brightness = MAX_BRIGHTNESS;
bd->props.brightness = MAX_BRIGHTNESS;
lcd->bd = bd;
/*
* it gets gamma table count available so it gets user
* know that.
*/
lcd->gamma_table_count =
sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int));
ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode);
if (ret < 0)
dev_err(&(spi->dev), "failed to add sysfs entries\n");
ret = device_create_file(&(spi->dev), &dev_attr_gamma_table);
if (ret < 0)
dev_err(&(spi->dev), "failed to add sysfs entries\n");
/*
* if lcd panel was on from bootloader like u-boot then
* do not lcd on.
*/
if (!lcd->lcd_pd->lcd_enabled) {
/*
* if lcd panel was off from bootloader then
* current lcd status is powerdown and then
* it enables lcd panel.
*/
lcd->power = FB_BLANK_POWERDOWN;
s6e63m0_power(lcd, FB_BLANK_UNBLANK);
} else
lcd->power = FB_BLANK_UNBLANK;
dev_set_drvdata(&spi->dev, lcd);
dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n");
return 0;
out_lcd_unregister:
lcd_device_unregister(ld);
out_free_lcd:
kfree(lcd);
return ret;
}
static int __devexit s6e63m0_remove(struct spi_device *spi)
{
struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
lcd_device_unregister(lcd->ld);
kfree(lcd);
return 0;
}
#if defined(CONFIG_PM)
unsigned int before_power;
static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg)
{
int ret = 0;
struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
before_power = lcd->power;
/*
* when lcd panel is suspend, lcd panel becomes off
* regardless of status.
*/
ret = s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
return ret;
}
static int s6e63m0_resume(struct spi_device *spi)
{
int ret = 0;
struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
/*
* after suspended, if lcd panel status is FB_BLANK_UNBLANK
* (at that time, before_power is FB_BLANK_UNBLANK) then
* it changes that status to FB_BLANK_POWERDOWN to get lcd on.
*/
if (before_power == FB_BLANK_UNBLANK)
lcd->power = FB_BLANK_POWERDOWN;
dev_dbg(&spi->dev, "before_power = %d\n", before_power);
ret = s6e63m0_power(lcd, before_power);
return ret;
}
#else
#define s6e63m0_suspend NULL
#define s6e63m0_resume NULL
#endif
/* Power down all displays on reboot, poweroff or halt. */
static void s6e63m0_shutdown(struct spi_device *spi)
{
struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
}
static struct spi_driver s6e63m0_driver = {
.driver = {
.name = "s6e63m0",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = s6e63m0_probe,
.remove = __devexit_p(s6e63m0_remove),
.shutdown = s6e63m0_shutdown,
.suspend = s6e63m0_suspend,
.resume = s6e63m0_resume,
};
static int __init s6e63m0_init(void)
{
return spi_register_driver(&s6e63m0_driver);
}
static void __exit s6e63m0_exit(void)
{
spi_unregister_driver(&s6e63m0_driver);
}
module_init(s6e63m0_init);
module_exit(s6e63m0_exit);
MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
MODULE_DESCRIPTION("S6E63M0 LCD Driver");
MODULE_LICENSE("GPL");
/* linux/drivers/video/samsung/s6e63m0_brightness.h
*
* Gamma level definitions.
*
* Copyright (c) 2009 Samsung Electronics
* InKi Dae <inki.dae@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _S6E63M0_BRIGHTNESS_H
#define _S6E63M0_BRIGHTNESS_H
#define MAX_GAMMA_LEVEL 11
#define GAMMA_TABLE_COUNT 21
/* gamma value: 2.2 */
static const unsigned int s6e63m0_22_300[] = {
0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6,
0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0,
0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb
};
static const unsigned int s6e63m0_22_280[] = {
0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6,
0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1,
0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6
};
static const unsigned int s6e63m0_22_260[] = {
0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6,
0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2,
0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1
};
static const unsigned int s6e63m0_22_240[] = {
0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9,
0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3,
0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA
};
static const unsigned int s6e63m0_22_220[] = {
0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8,
0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4,
0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2
};
static const unsigned int s6e63m0_22_200[] = {
0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA,
0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6,
0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA
};
static const unsigned int s6e63m0_22_170[] = {
0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB,
0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8,
0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB
};
static const unsigned int s6e63m0_22_140[] = {
0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC,
0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9,
0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E
};
static const unsigned int s6e63m0_22_110[] = {
0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF,
0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC,
0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D
};
static const unsigned int s6e63m0_22_90[] = {
0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0,
0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF,
0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82
};
static const unsigned int s6e63m0_22_30[] = {
0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8,
0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7,
0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51
};
/* gamma value: 1.9 */
static const unsigned int s6e63m0_19_300[] = {
0x18, 0x08, 0x24, 0x61, 0x5F, 0x39, 0xBA,
0xBD, 0xAD, 0xB1, 0xB6, 0xA5, 0xC4, 0xC5,
0xBC, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB
};
static const unsigned int s6e63m0_19_280[] = {
0x18, 0x08, 0x24, 0x61, 0x60, 0x39, 0xBB,
0xBE, 0xAD, 0xB2, 0xB6, 0xA6, 0xC5, 0xC7,
0xBD, 0x00, 0x9B, 0x00, 0x9E, 0x00, 0xD5
};
static const unsigned int s6e63m0_19_260[] = {
0x18, 0x08, 0x24, 0x63, 0x61, 0x3B, 0xBA,
0xBE, 0xAC, 0xB3, 0xB8, 0xA7, 0xC6, 0xC8,
0xBD, 0x00, 0x96, 0x00, 0x98, 0x00, 0xCF
};
static const unsigned int s6e63m0_19_240[] = {
0x18, 0x08, 0x24, 0x67, 0x64, 0x3F, 0xBB,
0xBE, 0xAD, 0xB3, 0xB9, 0xA7, 0xC8, 0xC9,
0xBE, 0x00, 0x90, 0x00, 0x92, 0x00, 0xC8
};
static const unsigned int s6e63m0_19_220[] = {
0x18, 0x08, 0x24, 0x68, 0x64, 0x40, 0xBC,
0xBF, 0xAF, 0xB4, 0xBA, 0xA9, 0xC8, 0xCA,
0xBE, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0xC0
};
static const unsigned int s6e63m0_19_200[] = {
0x18, 0x08, 0x24, 0x68, 0x64, 0x3F, 0xBE,
0xC0, 0xB0, 0xB6, 0xBB, 0xAB, 0xC8, 0xCB,
0xBF, 0x00, 0x85, 0x00, 0x86, 0x00, 0xB8
};
static const unsigned int s6e63m0_19_170[] = {
0x18, 0x08, 0x24, 0x69, 0x64, 0x40, 0xBF,
0xC1, 0xB0, 0xB9, 0xBE, 0xAD, 0xCB, 0xCD,
0xC2, 0x00, 0x7A, 0x00, 0x7B, 0x00, 0xAA
};
static const unsigned int s6e63m0_19_140[] = {
0x18, 0x08, 0x24, 0x6E, 0x65, 0x45, 0xC0,
0xC3, 0xB2, 0xBA, 0xBE, 0xAE, 0xCD, 0xD0,
0xC4, 0x00, 0x70, 0x00, 0x70, 0x00, 0x9C
};
static const unsigned int s6e63m0_19_110[] = {
0x18, 0x08, 0x24, 0x6F, 0x65, 0x46, 0xC2,
0xC4, 0xB3, 0xBF, 0xC2, 0xB2, 0xCF, 0xD1,
0xC6, 0x00, 0x64, 0x00, 0x64, 0x00, 0x8D
};
static const unsigned int s6e63m0_19_90[] = {
0x18, 0x08, 0x24, 0x74, 0x60, 0x4A, 0xC3,
0xC6, 0xB5, 0xBF, 0xC3, 0xB2, 0xD2, 0xD3,
0xC8, 0x00, 0x5B, 0x00, 0x5B, 0x00, 0x81
};
static const unsigned int s6e63m0_19_30[] = {
0x18, 0x08, 0x24, 0x84, 0x45, 0x4F, 0xCA,
0xCB, 0xBC, 0xC9, 0xCB, 0xBC, 0xDA, 0xDA,
0xD0, 0x00, 0x35, 0x00, 0x34, 0x00, 0x4E
};
/* gamma value: 1.7 */
static const unsigned int s6e63m0_17_300[] = {
0x18, 0x08, 0x24, 0x70, 0x70, 0x4F, 0xBF,
0xC2, 0xB2, 0xB8, 0xBC, 0xAC, 0xCB, 0xCD,
0xC3, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB
};
static const unsigned int s6e63m0_17_280[] = {
0x18, 0x08, 0x24, 0x71, 0x71, 0x50, 0xBF,
0xC2, 0xB2, 0xBA, 0xBE, 0xAE, 0xCB, 0xCD,
0xC3, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6
};
static const unsigned int s6e63m0_17_260[] = {
0x18, 0x08, 0x24, 0x72, 0x72, 0x50, 0xC0,
0xC3, 0xB4, 0xB9, 0xBE, 0xAE, 0xCC, 0xCF,
0xC4, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1
};
static const unsigned int s6e63m0_17_240[] = {
0x18, 0x08, 0x24, 0x71, 0x72, 0x4F, 0xC2,
0xC4, 0xB5, 0xBB, 0xBF, 0xB0, 0xCC, 0xCF,
0xC3, 0x00, 0x91, 0x00, 0x95, 0x00, 0xCA
};
static const unsigned int s6e63m0_17_220[] = {
0x18, 0x08, 0x24, 0x71, 0x73, 0x4F, 0xC2,
0xC5, 0xB5, 0xBD, 0xC0, 0xB2, 0xCD, 0xD1,
0xC5, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2
};
static const unsigned int s6e63m0_17_200[] = {
0x18, 0x08, 0x24, 0x72, 0x75, 0x51, 0xC2,
0xC6, 0xB5, 0xBF, 0xC1, 0xB3, 0xCE, 0xD1,
0xC6, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA
};
static const unsigned int s6e63m0_17_170[] = {
0x18, 0x08, 0x24, 0x75, 0x77, 0x54, 0xC3,
0xC7, 0xB7, 0xC0, 0xC3, 0xB4, 0xD1, 0xD3,
0xC9, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB
};
static const unsigned int s6e63m0_17_140[] = {
0x18, 0x08, 0x24, 0x7B, 0x77, 0x58, 0xC3,
0xC8, 0xB8, 0xC2, 0xC6, 0xB6, 0xD3, 0xD4,
0xCA, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E
};
static const unsigned int s6e63m0_17_110[] = {
0x18, 0x08, 0x24, 0x81, 0x7B, 0x5D, 0xC6,
0xCA, 0xBB, 0xC3, 0xC7, 0xB8, 0xD6, 0xD8,
0xCD, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D
};
static const unsigned int s6e63m0_17_90[] = {
0x18, 0x08, 0x24, 0x82, 0x7A, 0x5B, 0xC8,
0xCB, 0xBD, 0xC5, 0xCA, 0xBA, 0xD6, 0xD8,
0xCE, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82
};
static const unsigned int s6e63m0_17_30[] = {
0x18, 0x08, 0x24, 0x8F, 0x73, 0x63, 0xD1,
0xD0, 0xC5, 0xCC, 0xD1, 0xC2, 0xDE, 0xE0,
0xD6, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51
};
struct s6e63m0_gamma {
unsigned int *gamma_22_table[MAX_GAMMA_LEVEL];
unsigned int *gamma_19_table[MAX_GAMMA_LEVEL];
unsigned int *gamma_17_table[MAX_GAMMA_LEVEL];
};
static struct s6e63m0_gamma gamma_table = {
.gamma_22_table[0] = (unsigned int *)&s6e63m0_22_30,
.gamma_22_table[1] = (unsigned int *)&s6e63m0_22_90,
.gamma_22_table[2] = (unsigned int *)&s6e63m0_22_110,
.gamma_22_table[3] = (unsigned int *)&s6e63m0_22_140,
.gamma_22_table[4] = (unsigned int *)&s6e63m0_22_170,
.gamma_22_table[5] = (unsigned int *)&s6e63m0_22_200,
.gamma_22_table[6] = (unsigned int *)&s6e63m0_22_220,
.gamma_22_table[7] = (unsigned int *)&s6e63m0_22_240,
.gamma_22_table[8] = (unsigned int *)&s6e63m0_22_260,
.gamma_22_table[9] = (unsigned int *)&s6e63m0_22_280,
.gamma_22_table[10] = (unsigned int *)&s6e63m0_22_300,
.gamma_19_table[0] = (unsigned int *)&s6e63m0_19_30,
.gamma_19_table[1] = (unsigned int *)&s6e63m0_19_90,
.gamma_19_table[2] = (unsigned int *)&s6e63m0_19_110,
.gamma_19_table[3] = (unsigned int *)&s6e63m0_19_140,
.gamma_19_table[4] = (unsigned int *)&s6e63m0_19_170,
.gamma_19_table[5] = (unsigned int *)&s6e63m0_19_200,
.gamma_19_table[6] = (unsigned int *)&s6e63m0_19_220,
.gamma_19_table[7] = (unsigned int *)&s6e63m0_19_240,
.gamma_19_table[8] = (unsigned int *)&s6e63m0_19_260,
.gamma_19_table[9] = (unsigned int *)&s6e63m0_19_280,
.gamma_19_table[10] = (unsigned int *)&s6e63m0_19_300,
.gamma_17_table[0] = (unsigned int *)&s6e63m0_17_30,
.gamma_17_table[1] = (unsigned int *)&s6e63m0_17_90,
.gamma_17_table[2] = (unsigned int *)&s6e63m0_17_110,
.gamma_17_table[3] = (unsigned int *)&s6e63m0_17_140,
.gamma_17_table[4] = (unsigned int *)&s6e63m0_17_170,
.gamma_17_table[5] = (unsigned int *)&s6e63m0_17_200,
.gamma_17_table[6] = (unsigned int *)&s6e63m0_17_220,
.gamma_17_table[7] = (unsigned int *)&s6e63m0_17_240,
.gamma_17_table[8] = (unsigned int *)&s6e63m0_17_260,
.gamma_17_table[9] = (unsigned int *)&s6e63m0_17_280,
.gamma_17_table[10] = (unsigned int *)&s6e63m0_17_300,
};
#endif
/*
* Definitions and platform data for Analog Devices
* Backlight drivers ADP8860
*
* Copyright 2009-2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef __LINUX_I2C_ADP8860_H
#define __LINUX_I2C_ADP8860_H
#include <linux/leds.h>
#include <linux/types.h>
#define ID_ADP8860 8860
#define ADP8860_MAX_BRIGHTNESS 0x7F
#define FLAG_OFFT_SHIFT 8
/*
* LEDs subdevice platform data
*/
#define ADP8860_LED_DIS_BLINK (0 << FLAG_OFFT_SHIFT)
#define ADP8860_LED_OFFT_600ms (1 << FLAG_OFFT_SHIFT)
#define ADP8860_LED_OFFT_1200ms (2 << FLAG_OFFT_SHIFT)
#define ADP8860_LED_OFFT_1800ms (3 << FLAG_OFFT_SHIFT)
#define ADP8860_LED_ONT_200ms 0
#define ADP8860_LED_ONT_600ms 1
#define ADP8860_LED_ONT_800ms 2
#define ADP8860_LED_ONT_1200ms 3
#define ADP8860_LED_D7 (7)
#define ADP8860_LED_D6 (6)
#define ADP8860_LED_D5 (5)
#define ADP8860_LED_D4 (4)
#define ADP8860_LED_D3 (3)
#define ADP8860_LED_D2 (2)
#define ADP8860_LED_D1 (1)
/*
* Backlight subdevice platform data
*/
#define ADP8860_BL_D7 (1 << 6)
#define ADP8860_BL_D6 (1 << 5)
#define ADP8860_BL_D5 (1 << 4)
#define ADP8860_BL_D4 (1 << 3)
#define ADP8860_BL_D3 (1 << 2)
#define ADP8860_BL_D2 (1 << 1)
#define ADP8860_BL_D1 (1 << 0)
#define ADP8860_FADE_T_DIS 0 /* Fade Timer Disabled */
#define ADP8860_FADE_T_300ms 1 /* 0.3 Sec */
#define ADP8860_FADE_T_600ms 2
#define ADP8860_FADE_T_900ms 3
#define ADP8860_FADE_T_1200ms 4
#define ADP8860_FADE_T_1500ms 5
#define ADP8860_FADE_T_1800ms 6
#define ADP8860_FADE_T_2100ms 7
#define ADP8860_FADE_T_2400ms 8
#define ADP8860_FADE_T_2700ms 9
#define ADP8860_FADE_T_3000ms 10
#define ADP8860_FADE_T_3500ms 11
#define ADP8860_FADE_T_4000ms 12
#define ADP8860_FADE_T_4500ms 13
#define ADP8860_FADE_T_5000ms 14
#define ADP8860_FADE_T_5500ms 15 /* 5.5 Sec */
#define ADP8860_FADE_LAW_LINEAR 0
#define ADP8860_FADE_LAW_SQUARE 1
#define ADP8860_FADE_LAW_CUBIC1 2
#define ADP8860_FADE_LAW_CUBIC2 3
#define ADP8860_BL_AMBL_FILT_80ms 0 /* Light sensor filter time */
#define ADP8860_BL_AMBL_FILT_160ms 1
#define ADP8860_BL_AMBL_FILT_320ms 2
#define ADP8860_BL_AMBL_FILT_640ms 3
#define ADP8860_BL_AMBL_FILT_1280ms 4
#define ADP8860_BL_AMBL_FILT_2560ms 5
#define ADP8860_BL_AMBL_FILT_5120ms 6
#define ADP8860_BL_AMBL_FILT_10240ms 7 /* 10.24 sec */
/*
* Blacklight current 0..30mA
*/
#define ADP8860_BL_CUR_mA(I) ((I * 127) / 30)
/*
* L2 comparator current 0..1106uA
*/
#define ADP8860_L2_COMP_CURR_uA(I) ((I * 255) / 1106)
/*
* L3 comparator current 0..138uA
*/
#define ADP8860_L3_COMP_CURR_uA(I) ((I * 255) / 138)
struct adp8860_backlight_platform_data {
u8 bl_led_assign; /* 1 = Backlight 0 = Individual LED */
u8 bl_fade_in; /* Backlight Fade-In Timer */
u8 bl_fade_out; /* Backlight Fade-Out Timer */
u8 bl_fade_law; /* fade-on/fade-off transfer characteristic */
u8 en_ambl_sens; /* 1 = enable ambient light sensor */
u8 abml_filt; /* Light sensor filter time */
u8 l1_daylight_max; /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
u8 l1_daylight_dim; /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
u8 l2_office_max; /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
u8 l2_office_dim; /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
u8 l3_dark_max; /* use BL_CUR_mA(I) 0 <= I <= 30 mA */
u8 l3_dark_dim; /* typ = 0, use BL_CUR_mA(I) 0 <= I <= 30 mA */
u8 l2_trip; /* use L2_COMP_CURR_uA(I) 0 <= I <= 1106 uA */
u8 l2_hyst; /* use L2_COMP_CURR_uA(I) 0 <= I <= 1106 uA */
u8 l3_trip; /* use L3_COMP_CURR_uA(I) 0 <= I <= 551 uA */
u8 l3_hyst; /* use L3_COMP_CURR_uA(I) 0 <= I <= 551 uA */
/**
* Independent Current Sinks / LEDS
* Sinks not assigned to the Backlight can be exposed to
* user space using the LEDS CLASS interface
*/
int num_leds;
struct led_info *leds;
u8 led_fade_in; /* LED Fade-In Timer */
u8 led_fade_out; /* LED Fade-Out Timer */
u8 led_fade_law; /* fade-on/fade-off transfer characteristic */
u8 led_on_time;
/**
* Gain down disable. Setting this option does not allow the
* charge pump to switch to lower gains. NOT AVAILABLE on ADP8860
* 1 = the charge pump doesn't switch down in gain until all LEDs are 0.
* The charge pump switches up in gain as needed. This feature is
* useful if the ADP8863 charge pump is used to drive an external load.
* This feature must be used when utilizing small fly capacitors
* (0402 or smaller).
* 0 = the charge pump automatically switches up and down in gain.
* This provides optimal efficiency, but is not suitable for driving
* loads that are not connected through the ADP8863 diode drivers.
* Additionally, the charge pump fly capacitors should be low ESR
* and sized 0603 or greater.
*/
u8 gdwn_dis;
};
#endif /* __LINUX_I2C_ADP8860_H */
...@@ -69,6 +69,29 @@ struct lcd_device { ...@@ -69,6 +69,29 @@ struct lcd_device {
struct device dev; struct device dev;
}; };
struct lcd_platform_data {
/* reset lcd panel device. */
int (*reset)(struct lcd_device *ld);
/* on or off to lcd panel. if 'enable' is 0 then
lcd power off and 1, lcd power on. */
int (*power_on)(struct lcd_device *ld, int enable);
/* it indicates whether lcd panel was enabled
from bootloader or not. */
int lcd_enabled;
/* it means delay for stable time when it becomes low to high
or high to low that is dependent on whether reset gpio is
low active or high active. */
unsigned int reset_delay;
/* stable time needing to become lcd power on. */
unsigned int power_on_delay;
/* stable time needing to become lcd power off. */
unsigned int power_off_delay;
/* it could be used for any purpose. */
void *pdata;
};
static inline void lcd_set_power(struct lcd_device *ld, int power) static inline void lcd_set_power(struct lcd_device *ld, int power)
{ {
mutex_lock(&ld->update_lock); mutex_lock(&ld->update_lock);
......
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
* PCF50633 backlight device driver
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __LINUX_MFD_PCF50633_BACKLIGHT
#define __LINUX_MFD_PCF50633_BACKLIGHT
/*
* @default_brightness: Backlight brightness is initialized to this value
*
* Brightness to be used after the driver has been probed.
* Valid range 0-63.
*
* @default_brightness_limit: The actual brightness is limited by this value
*
* Brightness limit to be used after the driver has been probed. This is useful
* when it is not known how much power is available for the backlight during
* probe.
* Valid range 0-63. Can be changed later with pcf50633_bl_set_brightness_limit.
*
* @ramp_time: Display ramp time when changing brightness
*
* When changing the backlights brightness the change is not instant, instead
* it fades smooth from one state to another. This value specifies how long
* the fade should take. The lower the value the higher the fade time.
* Valid range 0-255
*/
struct pcf50633_bl_platform_data {
unsigned int default_brightness;
unsigned int default_brightness_limit;
uint8_t ramp_time;
};
struct pcf50633;
int pcf50633_bl_set_brightness_limit(struct pcf50633 *pcf, unsigned int limit);
#endif
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/mfd/pcf50633/backlight.h>
struct pcf50633; struct pcf50633;
...@@ -43,6 +44,8 @@ struct pcf50633_platform_data { ...@@ -43,6 +44,8 @@ struct pcf50633_platform_data {
void (*force_shutdown)(struct pcf50633 *); void (*force_shutdown)(struct pcf50633 *);
u8 resumers[5]; u8 resumers[5];
struct pcf50633_bl_platform_data *backlight_data;
}; };
struct pcf50633_irq { struct pcf50633_irq {
...@@ -152,6 +155,7 @@ struct pcf50633 { ...@@ -152,6 +155,7 @@ struct pcf50633 {
struct platform_device *mbc_pdev; struct platform_device *mbc_pdev;
struct platform_device *adc_pdev; struct platform_device *adc_pdev;
struct platform_device *input_pdev; struct platform_device *input_pdev;
struct platform_device *bl_pdev;
struct platform_device *regulator_pdev[PCF50633_NUM_REGULATORS]; struct platform_device *regulator_pdev[PCF50633_NUM_REGULATORS];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment