add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,264 @@
#
# Backlight & LCD drivers configuration
#
menuconfig BACKLIGHT_LCD_SUPPORT
bool "Backlight & LCD device support"
help
Enable this to be able to choose the drivers for controlling the
backlight and the LCD panel on some platforms, for example on PDAs.
#
# LCD
#
config LCD_CLASS_DEVICE
tristate "Lowlevel LCD controls"
depends on BACKLIGHT_LCD_SUPPORT
default m
help
This framework adds support for low-level control of LCD.
Some framebuffer devices connect to platform-specific LCD modules
in order to have a platform-specific way to control the flat panel
(contrast and applying power to the LCD (not to the backlight!)).
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
config LCD_CORGI
tristate "LCD Panel support for SHARP corgi/spitz model"
depends on LCD_CLASS_DEVICE && SPI_MASTER && PXA_SHARPSL
help
Say y here to support the LCD panels usually found on SHARP
corgi (C7x0) and spitz (Cxx00) models.
config LCD_LMS283GF05
tristate "Samsung LMS283GF05 LCD"
depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO
help
SPI driver for Samsung LMS283GF05. This provides basic support
for powering the LCD up/down through a sysfs interface.
config LCD_LTV350QV
tristate "Samsung LTV350QV LCD Panel"
depends on LCD_CLASS_DEVICE && SPI_MASTER
default n
help
If you have a Samsung LTV350QV LCD panel, say y to include a
power control driver for it. The panel starts up in power
off state, so you need this driver in order to see any
output.
The LTV350QV panel is present on all ATSTK1000 boards.
config LCD_ILI9320
tristate
depends on LCD_CLASS_DEVICE && BACKLIGHT_LCD_SUPPORT
default n
help
If you have a panel based on the ILI9320 controller chip
then say y to include a power driver for it.
config LCD_TDO24M
tristate "Toppoly TDO24M and TDO35S LCD Panels support"
depends on LCD_CLASS_DEVICE && SPI_MASTER
default n
help
If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to
include the support for it.
config LCD_VGG2432A4
tristate "VGG2432A4 LCM device support"
depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER
select LCD_ILI9320
default n
help
If you have a VGG2432A4 panel based on the ILI9320 controller chip
then say y to include a power driver for it.
config LCD_PLATFORM
tristate "Platform LCD controls"
depends on LCD_CLASS_DEVICE
help
This driver provides a platform-device registered LCD power
control interface.
config LCD_TOSA
tristate "Sharp SL-6000 LCD Driver"
depends on LCD_CLASS_DEVICE && SPI
depends on MACH_TOSA
default n
help
If you have an Sharp SL-6000 Zaurus say Y to enable a driver
for its LCD.
config LCD_HP700
tristate "HP Jornada 700 series LCD Driver"
depends on LCD_CLASS_DEVICE
depends on SA1100_JORNADA720_SSP && !PREEMPT
default y
help
If you have an HP Jornada 700 series handheld (710/720/728)
say Y to enable LCD control driver.
#
# Backlight
#
config BACKLIGHT_CLASS_DEVICE
tristate "Lowlevel Backlight controls"
depends on BACKLIGHT_LCD_SUPPORT
default m
help
This framework adds support for low-level control of the LCD
backlight. This includes support for brightness and power.
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
config BACKLIGHT_ATMEL_LCDC
bool "Atmel LCDC Contrast-as-Backlight control"
depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK
help
This provides a backlight control internal to the Atmel LCDC
driver. If the LCD "contrast control" on your board is wired
so it controls the backlight brightness, select this option to
export this as a PWM-based backlight control.
If in doubt, it's safe to enable this option; it doesn't kick
in unless the board's description says it's wired that way.
config BACKLIGHT_ATMEL_PWM
tristate "Atmel PWM backlight control"
depends on BACKLIGHT_CLASS_DEVICE && ATMEL_PWM
default n
help
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
which PWM instance to use and how to configure it.
To compile this driver as a module, choose M here: the module will be
called atmel-pwm-bl.
config BACKLIGHT_GENERIC
tristate "Generic (aka Sharp Corgi) Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE
default y
help
Say y to enable the generic platform backlight driver previously
known as the Corgi backlight driver. If you have a Sharp Zaurus
SL-C7xx, SL-Cxx00 or SL-6000x say y.
config BACKLIGHT_LOCOMO
tristate "Sharp LOCOMO LCD/Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && SHARP_LOCOMO
default y
help
If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
enable the LCD/backlight driver.
config BACKLIGHT_OMAP1
tristate "OMAP1 PWL-based LCD Backlight"
depends on BACKLIGHT_CLASS_DEVICE && ARCH_OMAP1
default y
help
This driver controls the LCD backlight level and power for
the PWL module of OMAP1 processors. Say Y if your board
uses this hardware.
config BACKLIGHT_HP680
tristate "HP Jornada 680 Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX
default y
help
If you have a HP Jornada 680, say y to enable the
backlight driver.
config BACKLIGHT_HP700
tristate "HP Jornada 700 series Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE
depends on SA1100_JORNADA720_SSP && !PREEMPT
default y
help
If you have an HP Jornada 700 series,
say Y to include backlight control driver.
config BACKLIGHT_PROGEAR
tristate "Frontpath ProGear Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && PCI && X86
default n
help
If you have a Frontpath ProGear say Y to enable the
backlight driver.
config BACKLIGHT_CARILLO_RANCH
tristate "Intel Carillo Ranch Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578
default n
help
If you have a Intel LE80578 (Carillo Ranch) say Y to enable the
backlight driver.
config BACKLIGHT_PWM
tristate "Generic PWM based Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && HAVE_PWM
help
If you have a LCD backlight adjustable by PWM, say Y to enable
this driver.
config BACKLIGHT_DA903X
tristate "Backlight Driver for DA9030/DA9034 using WLED"
depends on BACKLIGHT_CLASS_DEVICE && PMIC_DA903X
help
If you have a LCD backlight connected to the WLED output of DA9030
or DA9034 WLED output, say Y here to enable this driver.
config BACKLIGHT_MBP_NVIDIA
tristate "MacBook Pro Nvidia Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && X86
default n
help
If you have an Apple Macbook Pro with Nvidia graphics hardware say Y
to enable a driver for its backlight
config BACKLIGHT_TOSA
tristate "Sharp SL-6000 Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && I2C
depends on MACH_TOSA && LCD_TOSA
default n
help
If you have an Sharp SL-6000 Zaurus say Y to enable a driver
for its backlight
config BACKLIGHT_SAHARA
tristate "Tabletkiosk Sahara Touch-iT Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && X86
default n
help
If you have a Tabletkiosk Sahara Touch-iT, say y to enable the
backlight driver.
config BACKLIGHT_WM831X
tristate "WM831x PMIC Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && MFD_WM831X
help
If you have a backlight driven by the ISINK and DCDC of a
WM831x PMIC say y to enable the backlight driver for it.
config BACKLIGHT_ADX
tristate "Avionic Design Xanthos Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && ARCH_PXA_ADX
default y
help
Say Y to enable the backlight driver on Avionic Design Xanthos-based
boards.
config BACKLIGHT_ADP5520
tristate "Backlight Driver for ADP5520/ADP5501 using WLED"
depends on BACKLIGHT_CLASS_DEVICE && PMIC_ADP5520
help
If you have a LCD backlight connected to the BST/BL_SNK output of
ADP5520 or ADP5501, say Y here to enable this driver.
To compile this driver as a module, choose M here: the module will
be called adp5520_bl.

View File

@@ -0,0 +1,31 @@
# Backlight & LCD drivers
obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o
obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o
obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o
obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
obj-$(CONFIG_LCD_ILI9320) += ili9320.o
obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o
obj-$(CONFIG_LCD_TDO24M) += tdo24m.o
obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o
obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o
obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o
obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o
obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o

View File

@@ -0,0 +1,377 @@
/*
* Backlight driver for Analog Devices ADP5520/ADP5501 MFD PMICs
*
* Copyright 2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/mfd/adp5520.h>
struct adp5520_bl {
struct device *master;
struct adp5520_backlight_platfrom_data *pdata;
struct mutex lock;
unsigned long cached_daylight_max;
int id;
int current_brightness;
};
static int adp5520_bl_set(struct backlight_device *bl, int brightness)
{
struct adp5520_bl *data = bl_get_data(bl);
struct device *master = data->master;
int ret = 0;
if (data->pdata->en_ambl_sens) {
if ((brightness > 0) && (brightness < ADP5020_MAX_BRIGHTNESS)) {
/* Disable Ambient Light auto adjust */
ret |= adp5520_clr_bits(master, BL_CONTROL,
BL_AUTO_ADJ);
ret |= adp5520_write(master, DAYLIGHT_MAX, brightness);
} else {
/*
* MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
* restore daylight l3 sysfs brightness
*/
ret |= adp5520_write(master, DAYLIGHT_MAX,
data->cached_daylight_max);
ret |= adp5520_set_bits(master, BL_CONTROL,
BL_AUTO_ADJ);
}
} else {
ret |= adp5520_write(master, DAYLIGHT_MAX, brightness);
}
if (data->current_brightness && brightness == 0)
ret |= adp5520_set_bits(master,
MODE_STATUS, DIM_EN);
else if (data->current_brightness == 0 && brightness)
ret |= adp5520_clr_bits(master,
MODE_STATUS, DIM_EN);
if (!ret)
data->current_brightness = brightness;
return ret;
}
static int adp5520_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 adp5520_bl_set(bl, brightness);
}
static int adp5520_bl_get_brightness(struct backlight_device *bl)
{
struct adp5520_bl *data = bl_get_data(bl);
int error;
uint8_t reg_val;
error = adp5520_read(data->master, BL_VALUE, &reg_val);
return error ? data->current_brightness : reg_val;
}
static struct backlight_ops adp5520_bl_ops = {
.update_status = adp5520_bl_update_status,
.get_brightness = adp5520_bl_get_brightness,
};
static int adp5520_bl_setup(struct backlight_device *bl)
{
struct adp5520_bl *data = bl_get_data(bl);
struct device *master = data->master;
struct adp5520_backlight_platfrom_data *pdata = data->pdata;
int ret = 0;
ret |= adp5520_write(master, DAYLIGHT_MAX, pdata->l1_daylight_max);
ret |= adp5520_write(master, DAYLIGHT_DIM, pdata->l1_daylight_dim);
if (pdata->en_ambl_sens) {
data->cached_daylight_max = pdata->l1_daylight_max;
ret |= adp5520_write(master, OFFICE_MAX, pdata->l2_office_max);
ret |= adp5520_write(master, OFFICE_DIM, pdata->l2_office_dim);
ret |= adp5520_write(master, DARK_MAX, pdata->l3_dark_max);
ret |= adp5520_write(master, DARK_DIM, pdata->l3_dark_dim);
ret |= adp5520_write(master, L2_TRIP, pdata->l2_trip);
ret |= adp5520_write(master, L2_HYS, pdata->l2_hyst);
ret |= adp5520_write(master, L3_TRIP, pdata->l3_trip);
ret |= adp5520_write(master, L3_HYS, pdata->l3_hyst);
ret |= adp5520_write(master, ALS_CMPR_CFG,
ALS_CMPR_CFG_VAL(pdata->abml_filt, L3_EN));
}
ret |= adp5520_write(master, BL_CONTROL,
BL_CTRL_VAL(pdata->fade_led_law, pdata->en_ambl_sens));
ret |= adp5520_write(master, BL_FADE, FADE_VAL(pdata->fade_in,
pdata->fade_out));
ret |= adp5520_set_bits(master, MODE_STATUS, BL_EN | DIM_EN);
return ret;
}
static ssize_t adp5520_show(struct device *dev, char *buf, int reg)
{
struct adp5520_bl *data = dev_get_drvdata(dev);
int error;
uint8_t reg_val;
mutex_lock(&data->lock);
error = adp5520_read(data->master, reg, &reg_val);
mutex_unlock(&data->lock);
return sprintf(buf, "%u\n", reg_val);
}
static ssize_t adp5520_store(struct device *dev, const char *buf,
size_t count, int reg)
{
struct adp5520_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);
adp5520_write(data->master, reg, val);
mutex_unlock(&data->lock);
return count;
}
static ssize_t adp5520_bl_dark_max_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp5520_show(dev, buf, DARK_MAX);
}
static ssize_t adp5520_bl_dark_max_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
return adp5520_store(dev, buf, count, DARK_MAX);
}
static DEVICE_ATTR(dark_max, 0664, adp5520_bl_dark_max_show,
adp5520_bl_dark_max_store);
static ssize_t adp5520_bl_office_max_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp5520_show(dev, buf, OFFICE_MAX);
}
static ssize_t adp5520_bl_office_max_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
return adp5520_store(dev, buf, count, OFFICE_MAX);
}
static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show,
adp5520_bl_office_max_store);
static ssize_t adp5520_bl_daylight_max_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp5520_show(dev, buf, DAYLIGHT_MAX);
}
static ssize_t adp5520_bl_daylight_max_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct adp5520_bl *data = dev_get_drvdata(dev);
strict_strtoul(buf, 10, &data->cached_daylight_max);
return adp5520_store(dev, buf, count, DAYLIGHT_MAX);
}
static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show,
adp5520_bl_daylight_max_store);
static ssize_t adp5520_bl_dark_dim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp5520_show(dev, buf, DARK_DIM);
}
static ssize_t adp5520_bl_dark_dim_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return adp5520_store(dev, buf, count, DARK_DIM);
}
static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show,
adp5520_bl_dark_dim_store);
static ssize_t adp5520_bl_office_dim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp5520_show(dev, buf, OFFICE_DIM);
}
static ssize_t adp5520_bl_office_dim_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return adp5520_store(dev, buf, count, OFFICE_DIM);
}
static DEVICE_ATTR(office_dim, 0664, adp5520_bl_office_dim_show,
adp5520_bl_office_dim_store);
static ssize_t adp5520_bl_daylight_dim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return adp5520_show(dev, buf, DAYLIGHT_DIM);
}
static ssize_t adp5520_bl_daylight_dim_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return adp5520_store(dev, buf, count, DAYLIGHT_DIM);
}
static DEVICE_ATTR(daylight_dim, 0664, adp5520_bl_daylight_dim_show,
adp5520_bl_daylight_dim_store);
static struct attribute *adp5520_bl_attributes[] = {
&dev_attr_dark_max.attr,
&dev_attr_dark_dim.attr,
&dev_attr_office_max.attr,
&dev_attr_office_dim.attr,
&dev_attr_daylight_max.attr,
&dev_attr_daylight_dim.attr,
NULL
};
static const struct attribute_group adp5520_bl_attr_group = {
.attrs = adp5520_bl_attributes,
};
static int __devinit adp5520_bl_probe(struct platform_device *pdev)
{
struct backlight_device *bl;
struct adp5520_bl *data;
int ret = 0;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
data->master = pdev->dev.parent;
data->pdata = pdev->dev.platform_data;
if (data->pdata == NULL) {
dev_err(&pdev->dev, "missing platform data\n");
kfree(data);
return -ENODEV;
}
data->id = pdev->id;
data->current_brightness = 0;
mutex_init(&data->lock);
bl = backlight_device_register(pdev->name, data->master,
data, &adp5520_bl_ops);
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n");
kfree(data);
return PTR_ERR(bl);
}
bl->props.max_brightness =
bl->props.brightness = ADP5020_MAX_BRIGHTNESS;
if (data->pdata->en_ambl_sens)
ret = sysfs_create_group(&bl->dev.kobj,
&adp5520_bl_attr_group);
if (ret) {
dev_err(&pdev->dev, "failed to register sysfs\n");
backlight_device_unregister(bl);
kfree(data);
}
platform_set_drvdata(pdev, bl);
ret |= adp5520_bl_setup(bl);
backlight_update_status(bl);
return ret;
}
static int __devexit adp5520_bl_remove(struct platform_device *pdev)
{
struct backlight_device *bl = platform_get_drvdata(pdev);
struct adp5520_bl *data = bl_get_data(bl);
adp5520_clr_bits(data->master, MODE_STATUS, BL_EN);
if (data->pdata->en_ambl_sens)
sysfs_remove_group(&bl->dev.kobj,
&adp5520_bl_attr_group);
backlight_device_unregister(bl);
kfree(data);
return 0;
}
#ifdef CONFIG_PM
static int adp5520_bl_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct backlight_device *bl = platform_get_drvdata(pdev);
return adp5520_bl_set(bl, 0);
}
static int adp5520_bl_resume(struct platform_device *pdev)
{
struct backlight_device *bl = platform_get_drvdata(pdev);
backlight_update_status(bl);
return 0;
}
#else
#define adp5520_bl_suspend NULL
#define adp5520_bl_resume NULL
#endif
static struct platform_driver adp5520_bl_driver = {
.driver = {
.name = "adp5520-backlight",
.owner = THIS_MODULE,
},
.probe = adp5520_bl_probe,
.remove = __devexit_p(adp5520_bl_remove),
.suspend = adp5520_bl_suspend,
.resume = adp5520_bl_resume,
};
static int __init adp5520_bl_init(void)
{
return platform_driver_register(&adp5520_bl_driver);
}
module_init(adp5520_bl_init);
static void __exit adp5520_bl_exit(void)
{
platform_driver_unregister(&adp5520_bl_driver);
}
module_exit(adp5520_bl_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADP5520(01) Backlight Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:adp5520-backlight");

View File

@@ -0,0 +1,178 @@
/*
* linux/drivers/video/backlight/adx.c
*
* Copyright (C) 2009 Avionic Design GmbH
*
* 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.
*
* Written by Thierry Reding <thierry.reding@avionic-design.de>
*/
#include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
/* register definitions */
#define ADX_BACKLIGHT_CONTROL 0x00
#define ADX_BACKLIGHT_CONTROL_ENABLE (1 << 0)
#define ADX_BACKLIGHT_BRIGHTNESS 0x08
#define ADX_BACKLIGHT_STATUS 0x10
#define ADX_BACKLIGHT_ERROR 0x18
struct adxbl {
void __iomem *base;
};
static int adx_backlight_update_status(struct backlight_device *bldev)
{
struct adxbl *bl = bl_get_data(bldev);
u32 value;
value = bldev->props.brightness;
writel(value, bl->base + ADX_BACKLIGHT_BRIGHTNESS);
value = readl(bl->base + ADX_BACKLIGHT_CONTROL);
if (bldev->props.state & BL_CORE_FBBLANK)
value &= ~ADX_BACKLIGHT_CONTROL_ENABLE;
else
value |= ADX_BACKLIGHT_CONTROL_ENABLE;
writel(value, bl->base + ADX_BACKLIGHT_CONTROL);
return 0;
}
static int adx_backlight_get_brightness(struct backlight_device *bldev)
{
struct adxbl *bl = bl_get_data(bldev);
u32 brightness;
brightness = readl(bl->base + ADX_BACKLIGHT_BRIGHTNESS);
return brightness & 0xff;
}
static int adx_backlight_check_fb(struct fb_info *fb)
{
return 1;
}
static struct backlight_ops adx_backlight_ops = {
.options = 0,
.update_status = adx_backlight_update_status,
.get_brightness = adx_backlight_get_brightness,
.check_fb = adx_backlight_check_fb,
};
static int __devinit adx_backlight_probe(struct platform_device *pdev)
{
struct backlight_device *bldev;
struct resource *res;
struct adxbl *bl;
int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENXIO;
goto out;
}
res = devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), res->name);
if (!res) {
ret = -ENXIO;
goto out;
}
bl = devm_kzalloc(&pdev->dev, sizeof(*bl), GFP_KERNEL);
if (!bl) {
ret = -ENOMEM;
goto out;
}
bl->base = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
if (!bl->base) {
ret = -ENXIO;
goto out;
}
bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, bl,
&adx_backlight_ops);
if (!bldev) {
ret = -ENOMEM;
goto out;
}
bldev->props.max_brightness = 0xff;
bldev->props.brightness = 0xff;
bldev->props.power = FB_BLANK_UNBLANK;
platform_set_drvdata(pdev, bldev);
out:
return ret;
}
static int __devexit adx_backlight_remove(struct platform_device *pdev)
{
struct backlight_device *bldev;
int ret = 0;
bldev = platform_get_drvdata(pdev);
bldev->props.power = FB_BLANK_UNBLANK;
bldev->props.brightness = 0xff;
backlight_update_status(bldev);
backlight_device_unregister(bldev);
platform_set_drvdata(pdev, NULL);
return ret;
}
#ifdef CONFIG_PM
static int adx_backlight_suspend(struct platform_device *pdev,
pm_message_t state)
{
return 0;
}
static int adx_backlight_resume(struct platform_device *pdev)
{
return 0;
}
#else
#define adx_backlight_suspend NULL
#define adx_backlight_resume NULL
#endif
static struct platform_driver adx_backlight_driver = {
.probe = adx_backlight_probe,
.remove = __devexit_p(adx_backlight_remove),
.suspend = adx_backlight_suspend,
.resume = adx_backlight_resume,
.driver = {
.name = "adx-backlight",
.owner = THIS_MODULE,
},
};
static int __init adx_backlight_init(void)
{
return platform_driver_register(&adx_backlight_driver);
}
static void __exit adx_backlight_exit(void)
{
platform_driver_unregister(&adx_backlight_driver);
}
module_init(adx_backlight_init);
module_exit(adx_backlight_exit);
MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
MODULE_DESCRIPTION("Avionic Design Xanthos Backlight Driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,244 @@
/*
* Copyright (C) 2008 Atmel Corporation
*
* Backlight driver using Atmel PWM peripheral.
*
* 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.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/backlight.h>
#include <linux/atmel_pwm.h>
#include <linux/atmel-pwm-bl.h>
struct atmel_pwm_bl {
const struct atmel_pwm_bl_platform_data *pdata;
struct backlight_device *bldev;
struct platform_device *pdev;
struct pwm_channel pwmc;
int gpio_on;
};
static int atmel_pwm_bl_set_intensity(struct backlight_device *bd)
{
struct atmel_pwm_bl *pwmbl = bl_get_data(bd);
int intensity = bd->props.brightness;
int pwm_duty;
if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (pwmbl->pdata->pwm_active_low)
pwm_duty = pwmbl->pdata->pwm_duty_min + intensity;
else
pwm_duty = pwmbl->pdata->pwm_duty_max - intensity;
if (pwm_duty > pwmbl->pdata->pwm_duty_max)
pwm_duty = pwmbl->pdata->pwm_duty_max;
if (pwm_duty < pwmbl->pdata->pwm_duty_min)
pwm_duty = pwmbl->pdata->pwm_duty_min;
if (!intensity) {
if (pwmbl->gpio_on != -1) {
gpio_set_value(pwmbl->gpio_on,
0 ^ pwmbl->pdata->on_active_low);
}
pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty);
pwm_channel_disable(&pwmbl->pwmc);
} else {
pwm_channel_enable(&pwmbl->pwmc);
pwm_channel_writel(&pwmbl->pwmc, PWM_CUPD, pwm_duty);
if (pwmbl->gpio_on != -1) {
gpio_set_value(pwmbl->gpio_on,
1 ^ pwmbl->pdata->on_active_low);
}
}
return 0;
}
static int atmel_pwm_bl_get_intensity(struct backlight_device *bd)
{
struct atmel_pwm_bl *pwmbl = bl_get_data(bd);
u8 intensity;
if (pwmbl->pdata->pwm_active_low) {
intensity = pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY) -
pwmbl->pdata->pwm_duty_min;
} else {
intensity = pwmbl->pdata->pwm_duty_max -
pwm_channel_readl(&pwmbl->pwmc, PWM_CDTY);
}
return intensity;
}
static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl)
{
unsigned long pwm_rate = pwmbl->pwmc.mck;
unsigned long prescale = DIV_ROUND_UP(pwm_rate,
(pwmbl->pdata->pwm_frequency *
pwmbl->pdata->pwm_compare_max)) - 1;
/*
* Prescale must be power of two and maximum 0xf in size because of
* hardware limit. PWM speed will be:
* PWM module clock speed / (2 ^ prescale).
*/
prescale = fls(prescale);
if (prescale > 0xf)
prescale = 0xf;
pwm_channel_writel(&pwmbl->pwmc, PWM_CMR, prescale);
pwm_channel_writel(&pwmbl->pwmc, PWM_CDTY,
pwmbl->pdata->pwm_duty_min +
pwmbl->bldev->props.brightness);
pwm_channel_writel(&pwmbl->pwmc, PWM_CPRD,
pwmbl->pdata->pwm_compare_max);
dev_info(&pwmbl->pdev->dev, "Atmel PWM backlight driver "
"(%lu Hz)\n", pwmbl->pwmc.mck /
pwmbl->pdata->pwm_compare_max /
(1 << prescale));
return pwm_channel_enable(&pwmbl->pwmc);
}
static struct backlight_ops atmel_pwm_bl_ops = {
.get_brightness = atmel_pwm_bl_get_intensity,
.update_status = atmel_pwm_bl_set_intensity,
};
static int atmel_pwm_bl_probe(struct platform_device *pdev)
{
const struct atmel_pwm_bl_platform_data *pdata;
struct backlight_device *bldev;
struct atmel_pwm_bl *pwmbl;
int retval;
pwmbl = kzalloc(sizeof(struct atmel_pwm_bl), GFP_KERNEL);
if (!pwmbl)
return -ENOMEM;
pwmbl->pdev = pdev;
pdata = pdev->dev.platform_data;
if (!pdata) {
retval = -ENODEV;
goto err_free_mem;
}
if (pdata->pwm_compare_max < pdata->pwm_duty_max ||
pdata->pwm_duty_min > pdata->pwm_duty_max ||
pdata->pwm_frequency == 0) {
retval = -EINVAL;
goto err_free_mem;
}
pwmbl->pdata = pdata;
pwmbl->gpio_on = pdata->gpio_on;
retval = pwm_channel_alloc(pdata->pwm_channel, &pwmbl->pwmc);
if (retval)
goto err_free_mem;
if (pwmbl->gpio_on != -1) {
retval = gpio_request(pwmbl->gpio_on, "gpio_atmel_pwm_bl");
if (retval) {
pwmbl->gpio_on = -1;
goto err_free_pwm;
}
/* Turn display off by defatult. */
retval = gpio_direction_output(pwmbl->gpio_on,
0 ^ pdata->on_active_low);
if (retval)
goto err_free_gpio;
}
bldev = backlight_device_register("atmel-pwm-bl",
&pdev->dev, pwmbl, &atmel_pwm_bl_ops);
if (IS_ERR(bldev)) {
retval = PTR_ERR(bldev);
goto err_free_gpio;
}
pwmbl->bldev = bldev;
platform_set_drvdata(pdev, pwmbl);
/* Power up the backlight by default at middle intesity. */
bldev->props.power = FB_BLANK_UNBLANK;
bldev->props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min;
bldev->props.brightness = bldev->props.max_brightness / 2;
retval = atmel_pwm_bl_init_pwm(pwmbl);
if (retval)
goto err_free_bl_dev;
atmel_pwm_bl_set_intensity(bldev);
return 0;
err_free_bl_dev:
platform_set_drvdata(pdev, NULL);
backlight_device_unregister(bldev);
err_free_gpio:
if (pwmbl->gpio_on != -1)
gpio_free(pwmbl->gpio_on);
err_free_pwm:
pwm_channel_free(&pwmbl->pwmc);
err_free_mem:
kfree(pwmbl);
return retval;
}
static int __exit atmel_pwm_bl_remove(struct platform_device *pdev)
{
struct atmel_pwm_bl *pwmbl = platform_get_drvdata(pdev);
if (pwmbl->gpio_on != -1) {
gpio_set_value(pwmbl->gpio_on, 0);
gpio_free(pwmbl->gpio_on);
}
pwm_channel_disable(&pwmbl->pwmc);
pwm_channel_free(&pwmbl->pwmc);
backlight_device_unregister(pwmbl->bldev);
platform_set_drvdata(pdev, NULL);
kfree(pwmbl);
return 0;
}
static struct platform_driver atmel_pwm_bl_driver = {
.driver = {
.name = "atmel-pwm-bl",
},
/* REVISIT add suspend() and resume() */
.remove = __exit_p(atmel_pwm_bl_remove),
};
static int __init atmel_pwm_bl_init(void)
{
return platform_driver_probe(&atmel_pwm_bl_driver, atmel_pwm_bl_probe);
}
module_init(atmel_pwm_bl_init);
static void __exit atmel_pwm_bl_exit(void)
{
platform_driver_unregister(&atmel_pwm_bl_driver);
}
module_exit(atmel_pwm_bl_exit);
MODULE_AUTHOR("Hans-Christian egtvedt <hans-christian.egtvedt@atmel.com>");
MODULE_DESCRIPTION("Atmel PWM backlight driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,372 @@
/*
* Backlight Lowlevel Control Abstraction
*
* Copyright (C) 2003,2004 Hewlett-Packard Company
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/backlight.h>
#include <linux/notifier.h>
#include <linux/ctype.h>
#include <linux/err.h>
#include <linux/fb.h>
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
/* This callback gets called when something important happens inside a
* framebuffer driver. We're looking if that important event is blanking,
* and if it is, we're switching backlight power as well ...
*/
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data)
{
struct backlight_device *bd;
struct fb_event *evdata = data;
/* If we aren't interested in this event, skip it immediately ... */
if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
return 0;
bd = container_of(self, struct backlight_device, fb_notif);
mutex_lock(&bd->ops_lock);
if (bd->ops)
if (!bd->ops->check_fb ||
bd->ops->check_fb(evdata->info)) {
bd->props.fb_blank = *(int *)evdata->data;
if (bd->props.fb_blank == FB_BLANK_UNBLANK)
bd->props.state &= ~BL_CORE_FBBLANK;
else
bd->props.state |= BL_CORE_FBBLANK;
backlight_update_status(bd);
}
mutex_unlock(&bd->ops_lock);
return 0;
}
static int backlight_register_fb(struct backlight_device *bd)
{
memset(&bd->fb_notif, 0, sizeof(bd->fb_notif));
bd->fb_notif.notifier_call = fb_notifier_callback;
return fb_register_client(&bd->fb_notif);
}
static void backlight_unregister_fb(struct backlight_device *bd)
{
fb_unregister_client(&bd->fb_notif);
}
#else
static inline int backlight_register_fb(struct backlight_device *bd)
{
return 0;
}
static inline void backlight_unregister_fb(struct backlight_device *bd)
{
}
#endif /* CONFIG_FB */
static void backlight_generate_event(struct backlight_device *bd,
enum backlight_update_reason reason)
{
char *envp[2];
switch (reason) {
case BACKLIGHT_UPDATE_SYSFS:
envp[0] = "SOURCE=sysfs";
break;
case BACKLIGHT_UPDATE_HOTKEY:
envp[0] = "SOURCE=hotkey";
break;
default:
envp[0] = "SOURCE=unknown";
break;
}
envp[1] = NULL;
kobject_uevent_env(&bd->dev.kobj, KOBJ_CHANGE, envp);
sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness");
}
static ssize_t backlight_show_power(struct device *dev,
struct device_attribute *attr,char *buf)
{
struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.power);
}
static ssize_t backlight_store_power(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
struct backlight_device *bd = to_backlight_device(dev);
unsigned long power;
rc = strict_strtoul(buf, 0, &power);
if (rc)
return rc;
rc = -ENXIO;
mutex_lock(&bd->ops_lock);
if (bd->ops) {
pr_debug("backlight: set power to %lu\n", power);
if (bd->props.power != power) {
bd->props.power = power;
backlight_update_status(bd);
}
rc = count;
}
mutex_unlock(&bd->ops_lock);
return rc;
}
static ssize_t backlight_show_brightness(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.brightness);
}
static ssize_t backlight_store_brightness(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int rc;
struct backlight_device *bd = to_backlight_device(dev);
unsigned long brightness;
rc = strict_strtoul(buf, 0, &brightness);
if (rc)
return rc;
rc = -ENXIO;
mutex_lock(&bd->ops_lock);
if (bd->ops) {
if (brightness > bd->props.max_brightness)
rc = -EINVAL;
else {
pr_debug("backlight: set brightness to %lu\n",
brightness);
bd->props.brightness = brightness;
backlight_update_status(bd);
rc = count;
}
}
mutex_unlock(&bd->ops_lock);
backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS);
return rc;
}
static ssize_t backlight_show_max_brightness(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.max_brightness);
}
static ssize_t backlight_show_actual_brightness(struct device *dev,
struct device_attribute *attr, char *buf)
{
int rc = -ENXIO;
struct backlight_device *bd = to_backlight_device(dev);
mutex_lock(&bd->ops_lock);
if (bd->ops && bd->ops->get_brightness)
rc = sprintf(buf, "%d\n", bd->ops->get_brightness(bd));
mutex_unlock(&bd->ops_lock);
return rc;
}
static struct class *backlight_class;
static int backlight_suspend(struct device *dev, pm_message_t state)
{
struct backlight_device *bd = to_backlight_device(dev);
mutex_lock(&bd->ops_lock);
if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
bd->props.state |= BL_CORE_SUSPENDED;
backlight_update_status(bd);
}
mutex_unlock(&bd->ops_lock);
return 0;
}
static int backlight_resume(struct device *dev)
{
struct backlight_device *bd = to_backlight_device(dev);
mutex_lock(&bd->ops_lock);
if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
bd->props.state &= ~BL_CORE_SUSPENDED;
backlight_update_status(bd);
}
mutex_unlock(&bd->ops_lock);
return 0;
}
static void bl_device_release(struct device *dev)
{
struct backlight_device *bd = to_backlight_device(dev);
kfree(bd);
}
static struct device_attribute bl_device_attributes[] = {
__ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
__ATTR(brightness, 0644, backlight_show_brightness,
backlight_store_brightness),
__ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
NULL),
__ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
__ATTR_NULL,
};
/**
* backlight_force_update - tell the backlight subsystem that hardware state
* has changed
* @bd: the backlight device to update
*
* Updates the internal state of the backlight in response to a hardware event,
* and generate a uevent to notify userspace
*/
void backlight_force_update(struct backlight_device *bd,
enum backlight_update_reason reason)
{
mutex_lock(&bd->ops_lock);
if (bd->ops && bd->ops->get_brightness)
bd->props.brightness = bd->ops->get_brightness(bd);
mutex_unlock(&bd->ops_lock);
backlight_generate_event(bd, reason);
}
EXPORT_SYMBOL(backlight_force_update);
/**
* backlight_device_register - create and register a new object of
* backlight_device class.
* @name: the name of the new object(must be the same as the name of the
* respective framebuffer device).
* @parent: a pointer to the parent device
* @devdata: an optional pointer to be stored for private driver use. The
* methods may retrieve it by using bl_get_data(bd).
* @ops: the backlight operations structure.
*
* Creates and registers new backlight device. Returns either an
* ERR_PTR() or a pointer to the newly allocated device.
*/
struct backlight_device *backlight_device_register(const char *name,
struct device *parent, void *devdata, struct backlight_ops *ops)
{
struct backlight_device *new_bd;
int rc;
pr_debug("backlight_device_register: name=%s\n", name);
new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
if (!new_bd)
return ERR_PTR(-ENOMEM);
mutex_init(&new_bd->update_lock);
mutex_init(&new_bd->ops_lock);
new_bd->dev.class = backlight_class;
new_bd->dev.parent = parent;
new_bd->dev.release = bl_device_release;
dev_set_name(&new_bd->dev, name);
dev_set_drvdata(&new_bd->dev, devdata);
rc = device_register(&new_bd->dev);
if (rc) {
kfree(new_bd);
return ERR_PTR(rc);
}
rc = backlight_register_fb(new_bd);
if (rc) {
device_unregister(&new_bd->dev);
return ERR_PTR(rc);
}
new_bd->ops = ops;
#ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock(&pmac_backlight_mutex);
if (!pmac_backlight)
pmac_backlight = new_bd;
mutex_unlock(&pmac_backlight_mutex);
#endif
return new_bd;
}
EXPORT_SYMBOL(backlight_device_register);
/**
* backlight_device_unregister - unregisters a backlight device object.
* @bd: the backlight device object to be unregistered and freed.
*
* Unregisters a previously registered via backlight_device_register object.
*/
void backlight_device_unregister(struct backlight_device *bd)
{
if (!bd)
return;
#ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight == bd)
pmac_backlight = NULL;
mutex_unlock(&pmac_backlight_mutex);
#endif
mutex_lock(&bd->ops_lock);
bd->ops = NULL;
mutex_unlock(&bd->ops_lock);
backlight_unregister_fb(bd);
device_unregister(&bd->dev);
}
EXPORT_SYMBOL(backlight_device_unregister);
static void __exit backlight_class_exit(void)
{
class_destroy(backlight_class);
}
static int __init backlight_class_init(void)
{
backlight_class = class_create(THIS_MODULE, "backlight");
if (IS_ERR(backlight_class)) {
printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
PTR_ERR(backlight_class));
return PTR_ERR(backlight_class);
}
backlight_class->dev_attrs = bl_device_attributes;
backlight_class->suspend = backlight_suspend;
backlight_class->resume = backlight_resume;
return 0;
}
/*
* if this is compiled into the kernel, we need to ensure that the
* class is registered before users of the class try to register lcd's
*/
postcore_initcall(backlight_class_init);
module_exit(backlight_class_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>");
MODULE_DESCRIPTION("Backlight Lowlevel Control Abstraction");

View File

@@ -0,0 +1,643 @@
/*
* LCD/Backlight Driver for Sharp Zaurus Handhelds (various models)
*
* Copyright (c) 2004-2006 Richard Purdie
*
* Based on Sharp's 2.4 Backlight Driver
*
* Copyright (c) 2008 Marvell International Ltd.
* Converted to SPI device based LCD/Backlight device driver
* by Eric Miao <eric.miao@marvell.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.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/fb.h>
#include <linux/lcd.h>
#include <linux/spi/spi.h>
#include <linux/spi/corgi_lcd.h>
#include <asm/mach/sharpsl_param.h>
#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
/* Register Addresses */
#define RESCTL_ADRS 0x00
#define PHACTRL_ADRS 0x01
#define DUTYCTRL_ADRS 0x02
#define POWERREG0_ADRS 0x03
#define POWERREG1_ADRS 0x04
#define GPOR3_ADRS 0x05
#define PICTRL_ADRS 0x06
#define POLCTRL_ADRS 0x07
/* Register Bit Definitions */
#define RESCTL_QVGA 0x01
#define RESCTL_VGA 0x00
#define POWER1_VW_ON 0x01 /* VW Supply FET ON */
#define POWER1_GVSS_ON 0x02 /* GVSS(-8V) Power Supply ON */
#define POWER1_VDD_ON 0x04 /* VDD(8V),SVSS(-4V) Power Supply ON */
#define POWER1_VW_OFF 0x00 /* VW Supply FET OFF */
#define POWER1_GVSS_OFF 0x00 /* GVSS(-8V) Power Supply OFF */
#define POWER1_VDD_OFF 0x00 /* VDD(8V),SVSS(-4V) Power Supply OFF */
#define POWER0_COM_DCLK 0x01 /* COM Voltage DC Bias DAC Serial Data Clock */
#define POWER0_COM_DOUT 0x02 /* COM Voltage DC Bias DAC Serial Data Out */
#define POWER0_DAC_ON 0x04 /* DAC Power Supply ON */
#define POWER0_COM_ON 0x08 /* COM Power Supply ON */
#define POWER0_VCC5_ON 0x10 /* VCC5 Power Supply ON */
#define POWER0_DAC_OFF 0x00 /* DAC Power Supply OFF */
#define POWER0_COM_OFF 0x00 /* COM Power Supply OFF */
#define POWER0_VCC5_OFF 0x00 /* VCC5 Power Supply OFF */
#define PICTRL_INIT_STATE 0x01
#define PICTRL_INIOFF 0x02
#define PICTRL_POWER_DOWN 0x04
#define PICTRL_COM_SIGNAL_OFF 0x08
#define PICTRL_DAC_SIGNAL_OFF 0x10
#define POLCTRL_SYNC_POL_FALL 0x01
#define POLCTRL_EN_POL_FALL 0x02
#define POLCTRL_DATA_POL_FALL 0x04
#define POLCTRL_SYNC_ACT_H 0x08
#define POLCTRL_EN_ACT_L 0x10
#define POLCTRL_SYNC_POL_RISE 0x00
#define POLCTRL_EN_POL_RISE 0x00
#define POLCTRL_DATA_POL_RISE 0x00
#define POLCTRL_SYNC_ACT_L 0x00
#define POLCTRL_EN_ACT_H 0x00
#define PHACTRL_PHASE_MANUAL 0x01
#define DEFAULT_PHAD_QVGA (9)
#define DEFAULT_COMADJ (125)
struct corgi_lcd {
struct spi_device *spi_dev;
struct lcd_device *lcd_dev;
struct backlight_device *bl_dev;
int limit_mask;
int intensity;
int power;
int mode;
char buf[2];
int gpio_backlight_on;
int gpio_backlight_cont;
int gpio_backlight_cont_inverted;
void (*kick_battery)(void);
};
static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int reg, uint8_t val);
static struct corgi_lcd *the_corgi_lcd;
static unsigned long corgibl_flags;
#define CORGIBL_SUSPENDED 0x01
#define CORGIBL_BATTLOW 0x02
/*
* This is only a psuedo I2C interface. We can't use the standard kernel
* routines as the interface is write only. We just assume the data is acked...
*/
static void lcdtg_ssp_i2c_send(struct corgi_lcd *lcd, uint8_t data)
{
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, data);
udelay(10);
}
static void lcdtg_i2c_send_bit(struct corgi_lcd *lcd, uint8_t data)
{
lcdtg_ssp_i2c_send(lcd, data);
lcdtg_ssp_i2c_send(lcd, data | POWER0_COM_DCLK);
lcdtg_ssp_i2c_send(lcd, data);
}
static void lcdtg_i2c_send_start(struct corgi_lcd *lcd, uint8_t base)
{
lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK | POWER0_COM_DOUT);
lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK);
lcdtg_ssp_i2c_send(lcd, base);
}
static void lcdtg_i2c_send_stop(struct corgi_lcd *lcd, uint8_t base)
{
lcdtg_ssp_i2c_send(lcd, base);
lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK);
lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK | POWER0_COM_DOUT);
}
static void lcdtg_i2c_send_byte(struct corgi_lcd *lcd,
uint8_t base, uint8_t data)
{
int i;
for (i = 0; i < 8; i++) {
if (data & 0x80)
lcdtg_i2c_send_bit(lcd, base | POWER0_COM_DOUT);
else
lcdtg_i2c_send_bit(lcd, base);
data <<= 1;
}
}
static void lcdtg_i2c_wait_ack(struct corgi_lcd *lcd, uint8_t base)
{
lcdtg_i2c_send_bit(lcd, base);
}
static void lcdtg_set_common_voltage(struct corgi_lcd *lcd,
uint8_t base_data, uint8_t data)
{
/* Set Common Voltage to M62332FP via I2C */
lcdtg_i2c_send_start(lcd, base_data);
lcdtg_i2c_send_byte(lcd, base_data, 0x9c);
lcdtg_i2c_wait_ack(lcd, base_data);
lcdtg_i2c_send_byte(lcd, base_data, 0x00);
lcdtg_i2c_wait_ack(lcd, base_data);
lcdtg_i2c_send_byte(lcd, base_data, data);
lcdtg_i2c_wait_ack(lcd, base_data);
lcdtg_i2c_send_stop(lcd, base_data);
}
static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int adrs, uint8_t data)
{
struct spi_message msg;
struct spi_transfer xfer = {
.len = 1,
.cs_change = 1,
.tx_buf = lcd->buf,
};
lcd->buf[0] = ((adrs & 0x07) << 5) | (data & 0x1f);
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
return spi_sync(lcd->spi_dev, &msg);
}
/* Set Phase Adjust */
static void lcdtg_set_phadadj(struct corgi_lcd *lcd, int mode)
{
int adj;
switch(mode) {
case CORGI_LCD_MODE_VGA:
/* Setting for VGA */
adj = sharpsl_param.phadadj;
adj = (adj < 0) ? PHACTRL_PHASE_MANUAL :
PHACTRL_PHASE_MANUAL | ((adj & 0xf) << 1);
break;
case CORGI_LCD_MODE_QVGA:
default:
/* Setting for QVGA */
adj = (DEFAULT_PHAD_QVGA << 1) | PHACTRL_PHASE_MANUAL;
break;
}
corgi_ssp_lcdtg_send(lcd, PHACTRL_ADRS, adj);
}
static void corgi_lcd_power_on(struct corgi_lcd *lcd)
{
int comadj;
/* Initialize Internal Logic & Port */
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
PICTRL_POWER_DOWN | PICTRL_INIOFF |
PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF |
PICTRL_DAC_SIGNAL_OFF);
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF |
POWER0_COM_OFF | POWER0_VCC5_OFF);
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
/* VDD(+8V), SVSS(-4V) ON */
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
mdelay(3);
/* DAC ON */
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
POWER0_COM_OFF | POWER0_VCC5_OFF);
/* INIB = H, INI = L */
/* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF);
/* Set Common Voltage */
comadj = sharpsl_param.comadj;
if (comadj < 0)
comadj = DEFAULT_COMADJ;
lcdtg_set_common_voltage(lcd, POWER0_DAC_ON | POWER0_COM_OFF |
POWER0_VCC5_OFF, comadj);
/* VCC5 ON, DAC ON */
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
POWER0_COM_OFF | POWER0_VCC5_ON);
/* GVSS(-8V) ON, VDD ON */
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
mdelay(2);
/* COM SIGNAL ON (PICTL[3] = L) */
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, PICTRL_INIT_STATE);
/* COM ON, DAC ON, VCC5_ON */
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
POWER0_COM_ON | POWER0_VCC5_ON);
/* VW ON, GVSS ON, VDD ON */
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
POWER1_VW_ON | POWER1_GVSS_ON | POWER1_VDD_ON);
/* Signals output enable */
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, 0);
/* Set Phase Adjust */
lcdtg_set_phadadj(lcd, lcd->mode);
/* Initialize for Input Signals from ATI */
corgi_ssp_lcdtg_send(lcd, POLCTRL_ADRS,
POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE |
POLCTRL_DATA_POL_RISE | POLCTRL_SYNC_ACT_L |
POLCTRL_EN_ACT_H);
udelay(1000);
switch (lcd->mode) {
case CORGI_LCD_MODE_VGA:
corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_VGA);
break;
case CORGI_LCD_MODE_QVGA:
default:
corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_QVGA);
break;
}
}
static void corgi_lcd_power_off(struct corgi_lcd *lcd)
{
/* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
msleep(34);
/* (1)VW OFF */
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
/* (2)COM OFF */
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
/* (3)Set Common Voltage Bias 0V */
lcdtg_set_common_voltage(lcd, POWER0_DAC_ON | POWER0_COM_OFF |
POWER0_VCC5_ON, 0);
/* (4)GVSS OFF */
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
/* (5)VCC5 OFF */
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
/* (6)Set PDWN, INIOFF, DACOFF */
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
/* (7)DAC OFF */
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
/* (8)VDD OFF */
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
}
static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m)
{
struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
int mode = CORGI_LCD_MODE_QVGA;
if (m->xres == 640 || m->xres == 480)
mode = CORGI_LCD_MODE_VGA;
if (lcd->mode == mode)
return 0;
lcdtg_set_phadadj(lcd, mode);
switch (mode) {
case CORGI_LCD_MODE_VGA:
corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_VGA);
break;
case CORGI_LCD_MODE_QVGA:
default:
corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_QVGA);
break;
}
lcd->mode = mode;
return 0;
}
static int corgi_lcd_set_power(struct lcd_device *ld, int power)
{
struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
corgi_lcd_power_on(lcd);
if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
corgi_lcd_power_off(lcd);
lcd->power = power;
return 0;
}
static int corgi_lcd_get_power(struct lcd_device *ld)
{
struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
return lcd->power;
}
static struct lcd_ops corgi_lcd_ops = {
.get_power = corgi_lcd_get_power,
.set_power = corgi_lcd_set_power,
.set_mode = corgi_lcd_set_mode,
};
static int corgi_bl_get_intensity(struct backlight_device *bd)
{
struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev);
return lcd->intensity;
}
static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity)
{
int cont;
if (intensity > 0x10)
intensity += 0x10;
corgi_ssp_lcdtg_send(lcd, DUTYCTRL_ADRS, intensity);
/* Bit 5 via GPIO_BACKLIGHT_CONT */
cont = !!(intensity & 0x20) ^ lcd->gpio_backlight_cont_inverted;
if (gpio_is_valid(lcd->gpio_backlight_cont))
gpio_set_value(lcd->gpio_backlight_cont, cont);
if (gpio_is_valid(lcd->gpio_backlight_on))
gpio_set_value(lcd->gpio_backlight_on, intensity);
if (lcd->kick_battery)
lcd->kick_battery();
lcd->intensity = intensity;
return 0;
}
static int corgi_bl_update_status(struct backlight_device *bd)
{
struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev);
int intensity = bd->props.brightness;
if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (corgibl_flags & CORGIBL_SUSPENDED)
intensity = 0;
if ((corgibl_flags & CORGIBL_BATTLOW) && intensity > lcd->limit_mask)
intensity = lcd->limit_mask;
return corgi_bl_set_intensity(lcd, intensity);
}
void corgi_lcd_limit_intensity(int limit)
{
if (limit)
corgibl_flags |= CORGIBL_BATTLOW;
else
corgibl_flags &= ~CORGIBL_BATTLOW;
backlight_update_status(the_corgi_lcd->bl_dev);
}
EXPORT_SYMBOL(corgi_lcd_limit_intensity);
static struct backlight_ops corgi_bl_ops = {
.get_brightness = corgi_bl_get_intensity,
.update_status = corgi_bl_update_status,
};
#ifdef CONFIG_PM
static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state)
{
struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
corgibl_flags |= CORGIBL_SUSPENDED;
corgi_bl_set_intensity(lcd, 0);
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
return 0;
}
static int corgi_lcd_resume(struct spi_device *spi)
{
struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
corgibl_flags &= ~CORGIBL_SUSPENDED;
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
backlight_update_status(lcd->bl_dev);
return 0;
}
#else
#define corgi_lcd_suspend NULL
#define corgi_lcd_resume NULL
#endif
static int setup_gpio_backlight(struct corgi_lcd *lcd,
struct corgi_lcd_platform_data *pdata)
{
struct spi_device *spi = lcd->spi_dev;
int err;
lcd->gpio_backlight_on = -1;
lcd->gpio_backlight_cont = -1;
if (gpio_is_valid(pdata->gpio_backlight_on)) {
err = gpio_request(pdata->gpio_backlight_on, "BL_ON");
if (err) {
dev_err(&spi->dev, "failed to request GPIO%d for "
"backlight_on\n", pdata->gpio_backlight_on);
return err;
}
lcd->gpio_backlight_on = pdata->gpio_backlight_on;
gpio_direction_output(lcd->gpio_backlight_on, 0);
}
if (gpio_is_valid(pdata->gpio_backlight_cont)) {
err = gpio_request(pdata->gpio_backlight_cont, "BL_CONT");
if (err) {
dev_err(&spi->dev, "failed to request GPIO%d for "
"backlight_cont\n", pdata->gpio_backlight_cont);
goto err_free_backlight_on;
}
lcd->gpio_backlight_cont = pdata->gpio_backlight_cont;
/* spitz and akita use both GPIOs for backlight, and
* have inverted polarity of GPIO_BACKLIGHT_CONT
*/
if (gpio_is_valid(lcd->gpio_backlight_on)) {
lcd->gpio_backlight_cont_inverted = 1;
gpio_direction_output(lcd->gpio_backlight_cont, 1);
} else {
lcd->gpio_backlight_cont_inverted = 0;
gpio_direction_output(lcd->gpio_backlight_cont, 0);
}
}
return 0;
err_free_backlight_on:
if (gpio_is_valid(lcd->gpio_backlight_on))
gpio_free(lcd->gpio_backlight_on);
return err;
}
static int __devinit corgi_lcd_probe(struct spi_device *spi)
{
struct corgi_lcd_platform_data *pdata = spi->dev.platform_data;
struct corgi_lcd *lcd;
int ret = 0;
if (pdata == NULL) {
dev_err(&spi->dev, "platform data not available\n");
return -EINVAL;
}
lcd = kzalloc(sizeof(struct corgi_lcd), GFP_KERNEL);
if (!lcd) {
dev_err(&spi->dev, "failed to allocate memory\n");
return -ENOMEM;
}
lcd->spi_dev = spi;
lcd->lcd_dev = lcd_device_register("corgi_lcd", &spi->dev,
lcd, &corgi_lcd_ops);
if (IS_ERR(lcd->lcd_dev)) {
ret = PTR_ERR(lcd->lcd_dev);
goto err_free_lcd;
}
lcd->power = FB_BLANK_POWERDOWN;
lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA;
lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev,
lcd, &corgi_bl_ops);
if (IS_ERR(lcd->bl_dev)) {
ret = PTR_ERR(lcd->bl_dev);
goto err_unregister_lcd;
}
lcd->bl_dev->props.max_brightness = pdata->max_intensity;
lcd->bl_dev->props.brightness = pdata->default_intensity;
lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
ret = setup_gpio_backlight(lcd, pdata);
if (ret)
goto err_unregister_bl;
lcd->kick_battery = pdata->kick_battery;
dev_set_drvdata(&spi->dev, lcd);
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
backlight_update_status(lcd->bl_dev);
lcd->limit_mask = pdata->limit_mask;
the_corgi_lcd = lcd;
return 0;
err_unregister_bl:
backlight_device_unregister(lcd->bl_dev);
err_unregister_lcd:
lcd_device_unregister(lcd->lcd_dev);
err_free_lcd:
kfree(lcd);
return ret;
}
static int __devexit corgi_lcd_remove(struct spi_device *spi)
{
struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
lcd->bl_dev->props.brightness = 0;
backlight_update_status(lcd->bl_dev);
backlight_device_unregister(lcd->bl_dev);
if (gpio_is_valid(lcd->gpio_backlight_on))
gpio_free(lcd->gpio_backlight_on);
if (gpio_is_valid(lcd->gpio_backlight_cont))
gpio_free(lcd->gpio_backlight_cont);
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
lcd_device_unregister(lcd->lcd_dev);
kfree(lcd);
return 0;
}
static struct spi_driver corgi_lcd_driver = {
.driver = {
.name = "corgi-lcd",
.owner = THIS_MODULE,
},
.probe = corgi_lcd_probe,
.remove = __devexit_p(corgi_lcd_remove),
.suspend = corgi_lcd_suspend,
.resume = corgi_lcd_resume,
};
static int __init corgi_lcd_init(void)
{
return spi_register_driver(&corgi_lcd_driver);
}
module_init(corgi_lcd_init);
static void __exit corgi_lcd_exit(void)
{
spi_unregister_driver(&corgi_lcd_driver);
}
module_exit(corgi_lcd_exit);
MODULE_DESCRIPTION("LCD and backlight driver for SHARP C7x0/Cxx00");
MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:corgi-lcd");

View File

@@ -0,0 +1,287 @@
/*
* Copyright (c) Intel Corp. 2007.
* All Rights Reserved.
*
* Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
* develop this driver.
*
* This file is part of the Carillo Ranch video subsystem driver.
* The Carillo Ranch video subsystem driver 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.
*
* The Carillo Ranch video subsystem driver 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 driver; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
* Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
* Alan Hourihane <alanh-at-tungstengraphics-dot-com>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/lcd.h>
#include <linux/pci.h>
/* The LVDS- and panel power controls sits on the
* GPIO port of the ISA bridge.
*/
#define CRVML_DEVICE_LPC 0x27B8
#define CRVML_REG_GPIOBAR 0x48
#define CRVML_REG_GPIOEN 0x4C
#define CRVML_GPIOEN_BIT (1 << 4)
#define CRVML_PANEL_PORT 0x38
#define CRVML_LVDS_ON 0x00000001
#define CRVML_PANEL_ON 0x00000002
#define CRVML_BACKLIGHT_OFF 0x00000004
/* The PLL Clock register sits on Host bridge */
#define CRVML_DEVICE_MCH 0x5001
#define CRVML_REG_MCHBAR 0x44
#define CRVML_REG_MCHEN 0x54
#define CRVML_MCHEN_BIT (1 << 28)
#define CRVML_MCHMAP_SIZE 4096
#define CRVML_REG_CLOCK 0xc3c
#define CRVML_CLOCK_SHIFT 8
#define CRVML_CLOCK_MASK 0x00000f00
static struct pci_dev *lpc_dev;
static u32 gpio_bar;
struct cr_panel {
struct backlight_device *cr_backlight_device;
struct lcd_device *cr_lcd_device;
};
static int cr_backlight_set_intensity(struct backlight_device *bd)
{
int intensity = bd->props.brightness;
u32 addr = gpio_bar + CRVML_PANEL_PORT;
u32 cur = inl(addr);
if (bd->props.power == FB_BLANK_UNBLANK)
intensity = FB_BLANK_UNBLANK;
if (bd->props.fb_blank == FB_BLANK_UNBLANK)
intensity = FB_BLANK_UNBLANK;
if (bd->props.power == FB_BLANK_POWERDOWN)
intensity = FB_BLANK_POWERDOWN;
if (bd->props.fb_blank == FB_BLANK_POWERDOWN)
intensity = FB_BLANK_POWERDOWN;
if (intensity == FB_BLANK_UNBLANK) { /* FULL ON */
cur &= ~CRVML_BACKLIGHT_OFF;
outl(cur, addr);
} else if (intensity == FB_BLANK_POWERDOWN) { /* OFF */
cur |= CRVML_BACKLIGHT_OFF;
outl(cur, addr);
} /* anything else, don't bother */
return 0;
}
static int cr_backlight_get_intensity(struct backlight_device *bd)
{
u32 addr = gpio_bar + CRVML_PANEL_PORT;
u32 cur = inl(addr);
u8 intensity;
if (cur & CRVML_BACKLIGHT_OFF)
intensity = FB_BLANK_POWERDOWN;
else
intensity = FB_BLANK_UNBLANK;
return intensity;
}
static struct backlight_ops cr_backlight_ops = {
.get_brightness = cr_backlight_get_intensity,
.update_status = cr_backlight_set_intensity,
};
static void cr_panel_on(void)
{
u32 addr = gpio_bar + CRVML_PANEL_PORT;
u32 cur = inl(addr);
if (!(cur & CRVML_PANEL_ON)) {
/* Make sure LVDS controller is down. */
if (cur & 0x00000001) {
cur &= ~CRVML_LVDS_ON;
outl(cur, addr);
}
/* Power up Panel */
schedule_timeout(HZ / 10);
cur |= CRVML_PANEL_ON;
outl(cur, addr);
}
/* Power up LVDS controller */
if (!(cur & CRVML_LVDS_ON)) {
schedule_timeout(HZ / 10);
outl(cur | CRVML_LVDS_ON, addr);
}
}
static void cr_panel_off(void)
{
u32 addr = gpio_bar + CRVML_PANEL_PORT;
u32 cur = inl(addr);
/* Power down LVDS controller first to avoid high currents */
if (cur & CRVML_LVDS_ON) {
cur &= ~CRVML_LVDS_ON;
outl(cur, addr);
}
if (cur & CRVML_PANEL_ON) {
schedule_timeout(HZ / 10);
outl(cur & ~CRVML_PANEL_ON, addr);
}
}
static int cr_lcd_set_power(struct lcd_device *ld, int power)
{
if (power == FB_BLANK_UNBLANK)
cr_panel_on();
if (power == FB_BLANK_POWERDOWN)
cr_panel_off();
return 0;
}
static struct lcd_ops cr_lcd_ops = {
.set_power = cr_lcd_set_power,
};
static int cr_backlight_probe(struct platform_device *pdev)
{
struct backlight_device *bdp;
struct lcd_device *ldp;
struct cr_panel *crp;
u8 dev_en;
lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
CRVML_DEVICE_LPC, NULL);
if (!lpc_dev) {
printk("INTEL CARILLO RANCH LPC not found.\n");
return -ENODEV;
}
pci_read_config_byte(lpc_dev, CRVML_REG_GPIOEN, &dev_en);
if (!(dev_en & CRVML_GPIOEN_BIT)) {
printk(KERN_ERR
"Carillo Ranch GPIO device was not enabled.\n");
pci_dev_put(lpc_dev);
return -ENODEV;
}
bdp = backlight_device_register("cr-backlight",
&pdev->dev, NULL, &cr_backlight_ops);
if (IS_ERR(bdp)) {
pci_dev_put(lpc_dev);
return PTR_ERR(bdp);
}
ldp = lcd_device_register("cr-lcd", &pdev->dev, NULL, &cr_lcd_ops);
if (IS_ERR(ldp)) {
backlight_device_unregister(bdp);
pci_dev_put(lpc_dev);
return PTR_ERR(bdp);
}
pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
&gpio_bar);
gpio_bar &= ~0x3F;
crp = kzalloc(sizeof(*crp), GFP_KERNEL);
if (!crp) {
lcd_device_unregister(ldp);
backlight_device_unregister(bdp);
pci_dev_put(lpc_dev);
return -ENOMEM;
}
crp->cr_backlight_device = bdp;
crp->cr_lcd_device = ldp;
crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK;
crp->cr_backlight_device->props.brightness = 0;
crp->cr_backlight_device->props.max_brightness = 0;
cr_backlight_set_intensity(crp->cr_backlight_device);
cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_UNBLANK);
platform_set_drvdata(pdev, crp);
return 0;
}
static int cr_backlight_remove(struct platform_device *pdev)
{
struct cr_panel *crp = platform_get_drvdata(pdev);
crp->cr_backlight_device->props.power = FB_BLANK_POWERDOWN;
crp->cr_backlight_device->props.brightness = 0;
crp->cr_backlight_device->props.max_brightness = 0;
cr_backlight_set_intensity(crp->cr_backlight_device);
cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_POWERDOWN);
backlight_device_unregister(crp->cr_backlight_device);
lcd_device_unregister(crp->cr_lcd_device);
pci_dev_put(lpc_dev);
return 0;
}
static struct platform_driver cr_backlight_driver = {
.probe = cr_backlight_probe,
.remove = cr_backlight_remove,
.driver = {
.name = "cr_backlight",
},
};
static struct platform_device *crp;
static int __init cr_backlight_init(void)
{
int ret = platform_driver_register(&cr_backlight_driver);
if (ret)
return ret;
crp = platform_device_register_simple("cr_backlight", -1, NULL, 0);
if (IS_ERR(crp)) {
platform_driver_unregister(&cr_backlight_driver);
return PTR_ERR(crp);
}
printk("Carillo Ranch Backlight Driver Initialized.\n");
return 0;
}
static void __exit cr_backlight_exit(void)
{
platform_device_unregister(crp);
platform_driver_unregister(&cr_backlight_driver);
}
module_init(cr_backlight_init);
module_exit(cr_backlight_exit);
MODULE_AUTHOR("Tungsten Graphics Inc.");
MODULE_DESCRIPTION("Carillo Ranch Backlight Driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,207 @@
/*
* Backlight driver for Dialog Semiconductor DA9030/DA9034
*
* Copyright (C) 2008 Compulab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
*
* Copyright (C) 2006-2008 Marvell International Ltd.
* Eric Miao <eric.miao@marvell.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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/mfd/da903x.h>
#define DA9030_WLED_CONTROL 0x25
#define DA9030_WLED_CP_EN (1 << 6)
#define DA9030_WLED_TRIM(x) ((x) & 0x7)
#define DA9034_WLED_CONTROL1 0x3C
#define DA9034_WLED_CONTROL2 0x3D
#define DA9034_WLED_BOOST_EN (1 << 5)
#define DA9030_MAX_BRIGHTNESS 7
#define DA9034_MAX_BRIGHTNESS 0x7f
struct da903x_backlight_data {
struct device *da903x_dev;
int id;
int current_brightness;
};
static int da903x_backlight_set(struct backlight_device *bl, int brightness)
{
struct da903x_backlight_data *data = bl_get_data(bl);
struct device *dev = data->da903x_dev;
uint8_t val;
int ret = 0;
switch (data->id) {
case DA9034_ID_WLED:
ret = da903x_update(dev, DA9034_WLED_CONTROL1,
brightness, 0x7f);
if (ret)
return ret;
if (data->current_brightness && brightness == 0)
ret = da903x_clr_bits(dev,
DA9034_WLED_CONTROL2,
DA9034_WLED_BOOST_EN);
if (data->current_brightness == 0 && brightness)
ret = da903x_set_bits(dev,
DA9034_WLED_CONTROL2,
DA9034_WLED_BOOST_EN);
break;
case DA9030_ID_WLED:
val = DA9030_WLED_TRIM(brightness);
val |= brightness ? DA9030_WLED_CP_EN : 0;
ret = da903x_write(dev, DA9030_WLED_CONTROL, val);
break;
}
if (ret)
return ret;
data->current_brightness = brightness;
return 0;
}
static int da903x_backlight_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 da903x_backlight_set(bl, brightness);
}
static int da903x_backlight_get_brightness(struct backlight_device *bl)
{
struct da903x_backlight_data *data = bl_get_data(bl);
return data->current_brightness;
}
static struct backlight_ops da903x_backlight_ops = {
.update_status = da903x_backlight_update_status,
.get_brightness = da903x_backlight_get_brightness,
};
static int da903x_backlight_probe(struct platform_device *pdev)
{
struct da903x_backlight_data *data;
struct backlight_device *bl;
int max_brightness;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
switch (pdev->id) {
case DA9030_ID_WLED:
max_brightness = DA9030_MAX_BRIGHTNESS;
break;
case DA9034_ID_WLED:
max_brightness = DA9034_MAX_BRIGHTNESS;
break;
default:
dev_err(&pdev->dev, "invalid backlight device ID(%d)\n",
pdev->id);
kfree(data);
return -EINVAL;
}
data->id = pdev->id;
data->da903x_dev = pdev->dev.parent;
data->current_brightness = 0;
bl = backlight_device_register(pdev->name, data->da903x_dev,
data, &da903x_backlight_ops);
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n");
kfree(data);
return PTR_ERR(bl);
}
bl->props.max_brightness = max_brightness;
bl->props.brightness = max_brightness;
platform_set_drvdata(pdev, bl);
backlight_update_status(bl);
return 0;
}
static int da903x_backlight_remove(struct platform_device *pdev)
{
struct backlight_device *bl = platform_get_drvdata(pdev);
struct da903x_backlight_data *data = bl_get_data(bl);
backlight_device_unregister(bl);
kfree(data);
return 0;
}
#ifdef CONFIG_PM
static int da903x_backlight_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct backlight_device *bl = platform_get_drvdata(pdev);
return da903x_backlight_set(bl, 0);
}
static int da903x_backlight_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct backlight_device *bl = platform_get_drvdata(pdev);
backlight_update_status(bl);
return 0;
}
static struct dev_pm_ops da903x_backlight_pm_ops = {
.suspend = da903x_backlight_suspend,
.resume = da903x_backlight_resume,
};
#endif
static struct platform_driver da903x_backlight_driver = {
.driver = {
.name = "da903x-backlight",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &da903x_backlight_pm_ops,
#endif
},
.probe = da903x_backlight_probe,
.remove = da903x_backlight_remove,
};
static int __init da903x_backlight_init(void)
{
return platform_driver_register(&da903x_backlight_driver);
}
module_init(da903x_backlight_init);
static void __exit da903x_backlight_exit(void)
{
platform_driver_unregister(&da903x_backlight_driver);
}
module_exit(da903x_backlight_exit);
MODULE_DESCRIPTION("Backlight Driver for Dialog Semiconductor DA9030/DA9034");
MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
"Mike Rapoport <mike@compulab.co.il>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da903x-backlight");

View File

@@ -0,0 +1,147 @@
/*
* Generic Backlight Driver
*
* Copyright (c) 2004-2008 Richard Purdie
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/fb.h>
#include <linux/backlight.h>
static int genericbl_intensity;
static struct backlight_device *generic_backlight_device;
static struct generic_bl_info *bl_machinfo;
/* Flag to signal when the battery is low */
#define GENERICBL_BATTLOW BL_CORE_DRIVER1
static int genericbl_send_intensity(struct backlight_device *bd)
{
int intensity = bd->props.brightness;
if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
if (bd->props.state & BL_CORE_FBBLANK)
intensity = 0;
if (bd->props.state & BL_CORE_SUSPENDED)
intensity = 0;
if (bd->props.state & GENERICBL_BATTLOW)
intensity &= bl_machinfo->limit_mask;
bl_machinfo->set_bl_intensity(intensity);
genericbl_intensity = intensity;
if (bl_machinfo->kick_battery)
bl_machinfo->kick_battery();
return 0;
}
static int genericbl_get_intensity(struct backlight_device *bd)
{
return genericbl_intensity;
}
/*
* Called when the battery is low to limit the backlight intensity.
* If limit==0 clear any limit, otherwise limit the intensity
*/
void corgibl_limit_intensity(int limit)
{
struct backlight_device *bd = generic_backlight_device;
mutex_lock(&bd->ops_lock);
if (limit)
bd->props.state |= GENERICBL_BATTLOW;
else
bd->props.state &= ~GENERICBL_BATTLOW;
backlight_update_status(generic_backlight_device);
mutex_unlock(&bd->ops_lock);
}
EXPORT_SYMBOL(corgibl_limit_intensity);
static struct backlight_ops genericbl_ops = {
.options = BL_CORE_SUSPENDRESUME,
.get_brightness = genericbl_get_intensity,
.update_status = genericbl_send_intensity,
};
static int genericbl_probe(struct platform_device *pdev)
{
struct generic_bl_info *machinfo = pdev->dev.platform_data;
const char *name = "generic-bl";
struct backlight_device *bd;
bl_machinfo = machinfo;
if (!machinfo->limit_mask)
machinfo->limit_mask = -1;
if (machinfo->name)
name = machinfo->name;
bd = backlight_device_register (name,
&pdev->dev, NULL, &genericbl_ops);
if (IS_ERR (bd))
return PTR_ERR (bd);
platform_set_drvdata(pdev, bd);
bd->props.max_brightness = machinfo->max_intensity;
bd->props.power = FB_BLANK_UNBLANK;
bd->props.brightness = machinfo->default_intensity;
backlight_update_status(bd);
generic_backlight_device = bd;
printk("Generic Backlight Driver Initialized.\n");
return 0;
}
static int genericbl_remove(struct platform_device *pdev)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
bd->props.power = 0;
bd->props.brightness = 0;
backlight_update_status(bd);
backlight_device_unregister(bd);
printk("Generic Backlight Driver Unloaded\n");
return 0;
}
static struct platform_driver genericbl_driver = {
.probe = genericbl_probe,
.remove = genericbl_remove,
.driver = {
.name = "generic-bl",
},
};
static int __init genericbl_init(void)
{
return platform_driver_register(&genericbl_driver);
}
static void __exit genericbl_exit(void)
{
platform_driver_unregister(&genericbl_driver);
}
module_init(genericbl_init);
module_exit(genericbl_exit);
MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
MODULE_DESCRIPTION("Generic Backlight Driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,176 @@
/*
* Backlight Driver for HP Jornada 680
*
* Copyright (c) 2005 Andriy Skulysh
*
* Based on Sharp's Corgi Backlight Driver
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <cpu/dac.h>
#include <mach/hp6xx.h>
#include <asm/hd64461.h>
#define HP680_MAX_INTENSITY 255
#define HP680_DEFAULT_INTENSITY 10
static int hp680bl_suspended;
static int current_intensity = 0;
static DEFINE_SPINLOCK(bl_lock);
static void hp680bl_send_intensity(struct backlight_device *bd)
{
unsigned long flags;
u16 v;
int intensity = bd->props.brightness;
if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (hp680bl_suspended)
intensity = 0;
spin_lock_irqsave(&bl_lock, flags);
if (intensity && current_intensity == 0) {
sh_dac_enable(DAC_LCD_BRIGHTNESS);
v = inw(HD64461_GPBDR);
v &= ~HD64461_GPBDR_LCDOFF;
outw(v, HD64461_GPBDR);
sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
} else if (intensity == 0 && current_intensity != 0) {
sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
sh_dac_disable(DAC_LCD_BRIGHTNESS);
v = inw(HD64461_GPBDR);
v |= HD64461_GPBDR_LCDOFF;
outw(v, HD64461_GPBDR);
} else if (intensity) {
sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
}
spin_unlock_irqrestore(&bl_lock, flags);
current_intensity = intensity;
}
#ifdef CONFIG_PM
static int hp680bl_suspend(struct platform_device *pdev, pm_message_t state)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
hp680bl_suspended = 1;
hp680bl_send_intensity(bd);
return 0;
}
static int hp680bl_resume(struct platform_device *pdev)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
hp680bl_suspended = 0;
hp680bl_send_intensity(bd);
return 0;
}
#else
#define hp680bl_suspend NULL
#define hp680bl_resume NULL
#endif
static int hp680bl_set_intensity(struct backlight_device *bd)
{
hp680bl_send_intensity(bd);
return 0;
}
static int hp680bl_get_intensity(struct backlight_device *bd)
{
return current_intensity;
}
static struct backlight_ops hp680bl_ops = {
.get_brightness = hp680bl_get_intensity,
.update_status = hp680bl_set_intensity,
};
static int __devinit hp680bl_probe(struct platform_device *pdev)
{
struct backlight_device *bd;
bd = backlight_device_register ("hp680-bl", &pdev->dev, NULL,
&hp680bl_ops);
if (IS_ERR(bd))
return PTR_ERR(bd);
platform_set_drvdata(pdev, bd);
bd->props.max_brightness = HP680_MAX_INTENSITY;
bd->props.brightness = HP680_DEFAULT_INTENSITY;
hp680bl_send_intensity(bd);
return 0;
}
static int hp680bl_remove(struct platform_device *pdev)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
bd->props.brightness = 0;
bd->props.power = 0;
hp680bl_send_intensity(bd);
backlight_device_unregister(bd);
return 0;
}
static struct platform_driver hp680bl_driver = {
.probe = hp680bl_probe,
.remove = hp680bl_remove,
.suspend = hp680bl_suspend,
.resume = hp680bl_resume,
.driver = {
.name = "hp680-bl",
},
};
static struct platform_device *hp680bl_device;
static int __init hp680bl_init(void)
{
int ret;
ret = platform_driver_register(&hp680bl_driver);
if (ret)
return ret;
hp680bl_device = platform_device_register_simple("hp680-bl", -1,
NULL, 0);
if (IS_ERR(hp680bl_device)) {
platform_driver_unregister(&hp680bl_driver);
return PTR_ERR(hp680bl_device);
}
return 0;
}
static void __exit hp680bl_exit(void)
{
platform_device_unregister(hp680bl_device);
platform_driver_unregister(&hp680bl_driver);
}
module_init(hp680bl_init);
module_exit(hp680bl_exit);
MODULE_AUTHOR("Andriy Skulysh <askulysh@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 680 Backlight Driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,330 @@
/* drivers/video/backlight/ili9320.c
*
* ILI9320 LCD controller driver core.
*
* Copyright 2007 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* 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.
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/lcd.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <video/ili9320.h>
#include "ili9320.h"
static inline int ili9320_write_spi(struct ili9320 *ili,
unsigned int reg,
unsigned int value)
{
struct ili9320_spi *spi = &ili->access.spi;
unsigned char *addr = spi->buffer_addr;
unsigned char *data = spi->buffer_data;
/* spi message consits of:
* first byte: ID and operation
*/
addr[0] = spi->id | ILI9320_SPI_INDEX | ILI9320_SPI_WRITE;
addr[1] = reg >> 8;
addr[2] = reg;
/* second message is the data to transfer */
data[0] = spi->id | ILI9320_SPI_DATA | ILI9320_SPI_WRITE;
data[1] = value >> 8;
data[2] = value;
return spi_sync(spi->dev, &spi->message);
}
int ili9320_write(struct ili9320 *ili, unsigned int reg, unsigned int value)
{
dev_dbg(ili->dev, "write: reg=%02x, val=%04x\n", reg, value);
return ili->write(ili, reg, value);
}
EXPORT_SYMBOL_GPL(ili9320_write);
int ili9320_write_regs(struct ili9320 *ili,
struct ili9320_reg *values,
int nr_values)
{
int index;
int ret;
for (index = 0; index < nr_values; index++, values++) {
ret = ili9320_write(ili, values->address, values->value);
if (ret != 0)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(ili9320_write_regs);
static void ili9320_reset(struct ili9320 *lcd)
{
struct ili9320_platdata *cfg = lcd->platdata;
cfg->reset(1);
mdelay(50);
cfg->reset(0);
mdelay(50);
cfg->reset(1);
mdelay(100);
}
static inline int ili9320_init_chip(struct ili9320 *lcd)
{
int ret;
ili9320_reset(lcd);
ret = lcd->client->init(lcd, lcd->platdata);
if (ret != 0) {
dev_err(lcd->dev, "failed to initialise display\n");
return ret;
}
lcd->initialised = 1;
return 0;
}
static inline int ili9320_power_on(struct ili9320 *lcd)
{
if (!lcd->initialised)
ili9320_init_chip(lcd);
lcd->display1 |= (ILI9320_DISPLAY1_D(3) | ILI9320_DISPLAY1_BASEE);
ili9320_write(lcd, ILI9320_DISPLAY1, lcd->display1);
return 0;
}
static inline int ili9320_power_off(struct ili9320 *lcd)
{
lcd->display1 &= ~(ILI9320_DISPLAY1_D(3) | ILI9320_DISPLAY1_BASEE);
ili9320_write(lcd, ILI9320_DISPLAY1, lcd->display1);
return 0;
}
#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
static int ili9320_power(struct ili9320 *lcd, int power)
{
int ret = 0;
dev_dbg(lcd->dev, "power %d => %d\n", lcd->power, power);
if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
ret = ili9320_power_on(lcd);
else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
ret = ili9320_power_off(lcd);
if (ret == 0)
lcd->power = power;
else
dev_warn(lcd->dev, "failed to set power mode %d\n", power);
return ret;
}
static inline struct ili9320 *to_our_lcd(struct lcd_device *lcd)
{
return lcd_get_data(lcd);
}
static int ili9320_set_power(struct lcd_device *ld, int power)
{
struct ili9320 *lcd = to_our_lcd(ld);
return ili9320_power(lcd, power);
}
static int ili9320_get_power(struct lcd_device *ld)
{
struct ili9320 *lcd = to_our_lcd(ld);
return lcd->power;
}
static struct lcd_ops ili9320_ops = {
.get_power = ili9320_get_power,
.set_power = ili9320_set_power,
};
static void __devinit ili9320_setup_spi(struct ili9320 *ili,
struct spi_device *dev)
{
struct ili9320_spi *spi = &ili->access.spi;
ili->write = ili9320_write_spi;
spi->dev = dev;
/* fill the two messages we are going to use to send the data
* with, the first the address followed by the data. The datasheet
* says they should be done as two distinct cycles of the SPI CS line.
*/
spi->xfer[0].tx_buf = spi->buffer_addr;
spi->xfer[1].tx_buf = spi->buffer_data;
spi->xfer[0].len = 3;
spi->xfer[1].len = 3;
spi->xfer[0].bits_per_word = 8;
spi->xfer[1].bits_per_word = 8;
spi->xfer[0].cs_change = 1;
spi_message_init(&spi->message);
spi_message_add_tail(&spi->xfer[0], &spi->message);
spi_message_add_tail(&spi->xfer[1], &spi->message);
}
int __devinit ili9320_probe_spi(struct spi_device *spi,
struct ili9320_client *client)
{
struct ili9320_platdata *cfg = spi->dev.platform_data;
struct device *dev = &spi->dev;
struct ili9320 *ili;
struct lcd_device *lcd;
int ret = 0;
/* verify we where given some information */
if (cfg == NULL) {
dev_err(dev, "no platform data supplied\n");
return -EINVAL;
}
if (cfg->hsize <= 0 || cfg->vsize <= 0 || cfg->reset == NULL) {
dev_err(dev, "invalid platform data supplied\n");
return -EINVAL;
}
/* allocate and initialse our state */
ili = kzalloc(sizeof(struct ili9320), GFP_KERNEL);
if (ili == NULL) {
dev_err(dev, "no memory for device\n");
return -ENOMEM;
}
ili->access.spi.id = ILI9320_SPI_IDCODE | ILI9320_SPI_ID(1);
ili->dev = dev;
ili->client = client;
ili->power = FB_BLANK_POWERDOWN;
ili->platdata = cfg;
dev_set_drvdata(&spi->dev, ili);
ili9320_setup_spi(ili, spi);
lcd = lcd_device_register("ili9320", dev, ili, &ili9320_ops);
if (IS_ERR(lcd)) {
dev_err(dev, "failed to register lcd device\n");
ret = PTR_ERR(lcd);
goto err_free;
}
ili->lcd = lcd;
dev_info(dev, "initialising %s\n", client->name);
ret = ili9320_power(ili, FB_BLANK_UNBLANK);
if (ret != 0) {
dev_err(dev, "failed to set lcd power state\n");
goto err_unregister;
}
return 0;
err_unregister:
lcd_device_unregister(lcd);
err_free:
kfree(ili);
return ret;
}
EXPORT_SYMBOL_GPL(ili9320_probe_spi);
int __devexit ili9320_remove(struct ili9320 *ili)
{
ili9320_power(ili, FB_BLANK_POWERDOWN);
lcd_device_unregister(ili->lcd);
kfree(ili);
return 0;
}
EXPORT_SYMBOL_GPL(ili9320_remove);
#ifdef CONFIG_PM
int ili9320_suspend(struct ili9320 *lcd, pm_message_t state)
{
int ret;
dev_dbg(lcd->dev, "%s: event %d\n", __func__, state.event);
if (state.event == PM_EVENT_SUSPEND) {
ret = ili9320_power(lcd, FB_BLANK_POWERDOWN);
if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) {
ili9320_write(lcd, ILI9320_POWER1, lcd->power1 |
ILI9320_POWER1_SLP |
ILI9320_POWER1_DSTB);
lcd->initialised = 0;
}
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(ili9320_suspend);
int ili9320_resume(struct ili9320 *lcd)
{
dev_info(lcd->dev, "resuming from power state %d\n", lcd->power);
if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) {
ili9320_write(lcd, ILI9320_POWER1, 0x00);
}
return ili9320_power(lcd, FB_BLANK_UNBLANK);
}
EXPORT_SYMBOL_GPL(ili9320_resume);
#endif
/* Power down all displays on reboot, poweroff or halt */
void ili9320_shutdown(struct ili9320 *lcd)
{
ili9320_power(lcd, FB_BLANK_POWERDOWN);
}
EXPORT_SYMBOL_GPL(ili9320_shutdown);
MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
MODULE_DESCRIPTION("ILI9320 LCD Driver");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,80 @@
/* drivers/video/backlight/ili9320.h
*
* ILI9320 LCD controller driver core.
*
* Copyright 2007 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* http://armlinux.simtec.co.uk/
*
* 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.
*/
/* Holder for register and value pairs. */
struct ili9320_reg {
unsigned short address;
unsigned short value;
};
struct ili9320;
struct ili9320_client {
const char *name;
int (*init)(struct ili9320 *ili, struct ili9320_platdata *cfg);
};
/* Device attached via an SPI bus. */
struct ili9320_spi {
struct spi_device *dev;
struct spi_message message;
struct spi_transfer xfer[2];
unsigned char id;
unsigned char buffer_addr[4];
unsigned char buffer_data[4];
};
/* ILI9320 device state. */
struct ili9320 {
union {
struct ili9320_spi spi; /* SPI attachged device. */
} access; /* Register access method. */
struct device *dev;
struct lcd_device *lcd; /* LCD device we created. */
struct ili9320_client *client;
struct ili9320_platdata *platdata;
int power; /* current power state. */
int initialised;
unsigned short display1;
unsigned short power1;
int (*write)(struct ili9320 *ili, unsigned int reg, unsigned int val);
};
/* ILI9320 register access routines */
extern int ili9320_write(struct ili9320 *ili,
unsigned int reg, unsigned int value);
extern int ili9320_write_regs(struct ili9320 *ili,
struct ili9320_reg *values,
int nr_values);
/* Device probe */
extern int ili9320_probe_spi(struct spi_device *spi,
struct ili9320_client *cli);
extern int ili9320_remove(struct ili9320 *lcd);
extern void ili9320_shutdown(struct ili9320 *lcd);
/* PM */
extern int ili9320_suspend(struct ili9320 *lcd, pm_message_t state);
extern int ili9320_resume(struct ili9320 *lcd);

View File

@@ -0,0 +1,161 @@
/*
*
* Backlight driver for HP Jornada 700 series (710/720/728)
* Copyright (C) 2006-2009 Kristoffer Ericson <kristoffer.ericson@gmail.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 or any later version as published by the Free Software Foundation.
*
*/
#include <linux/backlight.h>
#include <linux/device.h>
#include <linux/fb.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <mach/jornada720.h>
#include <mach/hardware.h>
#include <video/s1d13xxxfb.h>
#define BL_MAX_BRIGHT 255
#define BL_DEF_BRIGHT 25
static int jornada_bl_get_brightness(struct backlight_device *bd)
{
int ret;
/* check if backlight is on */
if (!(PPSR & PPC_LDD1))
return 0;
jornada_ssp_start();
/* cmd should return txdummy */
ret = jornada_ssp_byte(GETBRIGHTNESS);
if (jornada_ssp_byte(GETBRIGHTNESS) != TXDUMMY) {
printk(KERN_ERR "bl : get brightness timeout\n");
jornada_ssp_end();
return -ETIMEDOUT;
} else /* exchange txdummy for value */
ret = jornada_ssp_byte(TXDUMMY);
jornada_ssp_end();
return (BL_MAX_BRIGHT - ret);
}
static int jornada_bl_update_status(struct backlight_device *bd)
{
int ret = 0;
jornada_ssp_start();
/* If backlight is off then really turn it off */
if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) {
ret = jornada_ssp_byte(BRIGHTNESSOFF);
if (ret != TXDUMMY) {
printk(KERN_INFO "bl : brightness off timeout\n");
/* turn off backlight */
PPSR &= ~PPC_LDD1;
PPDR |= PPC_LDD1;
ret = -ETIMEDOUT;
}
} else /* turn on backlight */
PPSR |= PPC_LDD1;
/* send command to our mcu */
if (jornada_ssp_byte(SETBRIGHTNESS) != TXDUMMY) {
printk(KERN_INFO "bl : failed to set brightness\n");
ret = -ETIMEDOUT;
goto out;
}
/* at this point we expect that the mcu has accepted
our command and is waiting for our new value
please note that maximum brightness is 255,
but due to physical layout it is equal to 0, so we simply
invert the value (MAX VALUE - NEW VALUE). */
if (jornada_ssp_byte(BL_MAX_BRIGHT - bd->props.brightness) != TXDUMMY) {
printk(KERN_ERR "bl : set brightness failed\n");
ret = -ETIMEDOUT;
}
/* If infact we get an TXDUMMY as output we are happy and dont
make any further comments about it */
out:
jornada_ssp_end();
return ret;
}
static struct backlight_ops jornada_bl_ops = {
.get_brightness = jornada_bl_get_brightness,
.update_status = jornada_bl_update_status,
.options = BL_CORE_SUSPENDRESUME,
};
static int jornada_bl_probe(struct platform_device *pdev)
{
int ret;
struct backlight_device *bd;
bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL, &jornada_bl_ops);
if (IS_ERR(bd)) {
ret = PTR_ERR(bd);
printk(KERN_ERR "bl : failed to register device, err=%x\n", ret);
return ret;
}
bd->props.power = FB_BLANK_UNBLANK;
bd->props.brightness = BL_DEF_BRIGHT;
/* note. make sure max brightness is set otherwise
you will get seemingly non-related errors when
trying to change brightness */
bd->props.max_brightness = BL_MAX_BRIGHT;
jornada_bl_update_status(bd);
platform_set_drvdata(pdev, bd);
printk(KERN_INFO "HP Jornada 700 series backlight driver\n");
return 0;
}
static int jornada_bl_remove(struct platform_device *pdev)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
backlight_device_unregister(bd);
return 0;
}
static struct platform_driver jornada_bl_driver = {
.probe = jornada_bl_probe,
.remove = jornada_bl_remove,
.driver = {
.name = "jornada_bl",
},
};
int __init jornada_bl_init(void)
{
return platform_driver_register(&jornada_bl_driver);
}
void __exit jornada_bl_exit(void)
{
platform_driver_unregister(&jornada_bl_driver);
}
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 Backlight driver");
MODULE_LICENSE("GPL");
module_init(jornada_bl_init);
module_exit(jornada_bl_exit);

View File

@@ -0,0 +1,153 @@
/*
*
* LCD driver for HP Jornada 700 series (710/720/728)
* Copyright (C) 2006-2009 Kristoffer Ericson <kristoffer.ericson@gmail.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 or any later version as published by the Free Software Foundation.
*
*/
#include <linux/device.h>
#include <linux/fb.h>
#include <linux/kernel.h>
#include <linux/lcd.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <mach/jornada720.h>
#include <mach/hardware.h>
#include <video/s1d13xxxfb.h>
#define LCD_MAX_CONTRAST 0xff
#define LCD_DEF_CONTRAST 0x80
static int jornada_lcd_get_power(struct lcd_device *dev)
{
/* LDD2 in PPC = LCD POWER */
if (PPSR & PPC_LDD2)
return FB_BLANK_UNBLANK; /* PW ON */
else
return FB_BLANK_POWERDOWN; /* PW OFF */
}
static int jornada_lcd_get_contrast(struct lcd_device *dev)
{
int ret;
if (jornada_lcd_get_power(dev) != FB_BLANK_UNBLANK)
return 0;
jornada_ssp_start();
if (jornada_ssp_byte(GETCONTRAST) != TXDUMMY) {
printk(KERN_ERR "lcd: get contrast failed\n");
jornada_ssp_end();
return -ETIMEDOUT;
} else {
ret = jornada_ssp_byte(TXDUMMY);
jornada_ssp_end();
return ret;
}
}
static int jornada_lcd_set_contrast(struct lcd_device *dev, int value)
{
int ret;
jornada_ssp_start();
/* start by sending our set contrast cmd to mcu */
ret = jornada_ssp_byte(SETCONTRAST);
/* push the new value */
if (jornada_ssp_byte(value) != TXDUMMY) {
printk(KERN_ERR "lcd : set contrast failed\n");
jornada_ssp_end();
return -ETIMEDOUT;
}
/* if we get here we can assume everything went well */
jornada_ssp_end();
return 0;
}
static int jornada_lcd_set_power(struct lcd_device *dev, int power)
{
if (power != FB_BLANK_UNBLANK) {
PPSR &= ~PPC_LDD2;
PPDR |= PPC_LDD2;
} else
PPSR |= PPC_LDD2;
return 0;
}
static struct lcd_ops jornada_lcd_props = {
.get_contrast = jornada_lcd_get_contrast,
.set_contrast = jornada_lcd_set_contrast,
.get_power = jornada_lcd_get_power,
.set_power = jornada_lcd_set_power,
};
static int jornada_lcd_probe(struct platform_device *pdev)
{
struct lcd_device *lcd_device;
int ret;
lcd_device = lcd_device_register(S1D_DEVICENAME, &pdev->dev, NULL, &jornada_lcd_props);
if (IS_ERR(lcd_device)) {
ret = PTR_ERR(lcd_device);
printk(KERN_ERR "lcd : failed to register device\n");
return ret;
}
platform_set_drvdata(pdev, lcd_device);
/* lets set our default values */
jornada_lcd_set_contrast(lcd_device, LCD_DEF_CONTRAST);
jornada_lcd_set_power(lcd_device, FB_BLANK_UNBLANK);
/* give it some time to startup */
msleep(100);
return 0;
}
static int jornada_lcd_remove(struct platform_device *pdev)
{
struct lcd_device *lcd_device = platform_get_drvdata(pdev);
lcd_device_unregister(lcd_device);
return 0;
}
static struct platform_driver jornada_lcd_driver = {
.probe = jornada_lcd_probe,
.remove = jornada_lcd_remove,
.driver = {
.name = "jornada_lcd",
},
};
int __init jornada_lcd_init(void)
{
return platform_driver_register(&jornada_lcd_driver);
}
void __exit jornada_lcd_exit(void)
{
platform_driver_unregister(&jornada_lcd_driver);
}
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 LCD driver");
MODULE_LICENSE("GPL");
module_init(jornada_lcd_init);
module_exit(jornada_lcd_exit);

View File

@@ -0,0 +1,204 @@
/*
* Backlight Driver for the KB3886 Backlight
*
* Copyright (c) 2007-2008 Claudio Nieder
*
* Based on corgi_bl.c by Richard Purdie and kb3886 driver by Robert Woerle
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#define KB3886_PARENT 0x64
#define KB3886_IO 0x60
#define KB3886_ADC_DAC_PWM 0xC4
#define KB3886_PWM0_WRITE 0x81
#define KB3886_PWM0_READ 0x41
static DEFINE_MUTEX(bl_mutex);
static void kb3886_bl_set_intensity(int intensity)
{
mutex_lock(&bl_mutex);
intensity = intensity&0xff;
outb(KB3886_ADC_DAC_PWM, KB3886_PARENT);
msleep(10);
outb(KB3886_PWM0_WRITE, KB3886_IO);
msleep(10);
outb(intensity, KB3886_IO);
mutex_unlock(&bl_mutex);
}
struct kb3886bl_machinfo {
int max_intensity;
int default_intensity;
int limit_mask;
void (*set_bl_intensity)(int intensity);
};
static struct kb3886bl_machinfo kb3886_bl_machinfo = {
.max_intensity = 0xff,
.default_intensity = 0xa0,
.limit_mask = 0x7f,
.set_bl_intensity = kb3886_bl_set_intensity,
};
static struct platform_device kb3886bl_device = {
.name = "kb3886-bl",
.dev = {
.platform_data = &kb3886_bl_machinfo,
},
.id = -1,
};
static struct platform_device *devices[] __initdata = {
&kb3886bl_device,
};
/*
* Back to driver
*/
static int kb3886bl_intensity;
static struct backlight_device *kb3886_backlight_device;
static struct kb3886bl_machinfo *bl_machinfo;
static unsigned long kb3886bl_flags;
#define KB3886BL_SUSPENDED 0x01
static struct dmi_system_id __initdata kb3886bl_device_table[] = {
{
.ident = "Sahara Touch-iT",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SDV"),
DMI_MATCH(DMI_PRODUCT_NAME, "iTouch T201"),
},
},
{ }
};
static int kb3886bl_send_intensity(struct backlight_device *bd)
{
int intensity = bd->props.brightness;
if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (kb3886bl_flags & KB3886BL_SUSPENDED)
intensity = 0;
bl_machinfo->set_bl_intensity(intensity);
kb3886bl_intensity = intensity;
return 0;
}
#ifdef CONFIG_PM
static int kb3886bl_suspend(struct platform_device *pdev, pm_message_t state)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
kb3886bl_flags |= KB3886BL_SUSPENDED;
backlight_update_status(bd);
return 0;
}
static int kb3886bl_resume(struct platform_device *pdev)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
kb3886bl_flags &= ~KB3886BL_SUSPENDED;
backlight_update_status(bd);
return 0;
}
#else
#define kb3886bl_suspend NULL
#define kb3886bl_resume NULL
#endif
static int kb3886bl_get_intensity(struct backlight_device *bd)
{
return kb3886bl_intensity;
}
static struct backlight_ops kb3886bl_ops = {
.get_brightness = kb3886bl_get_intensity,
.update_status = kb3886bl_send_intensity,
};
static int kb3886bl_probe(struct platform_device *pdev)
{
struct kb3886bl_machinfo *machinfo = pdev->dev.platform_data;
bl_machinfo = machinfo;
if (!machinfo->limit_mask)
machinfo->limit_mask = -1;
kb3886_backlight_device = backlight_device_register("kb3886-bl",
&pdev->dev, NULL, &kb3886bl_ops);
if (IS_ERR(kb3886_backlight_device))
return PTR_ERR(kb3886_backlight_device);
platform_set_drvdata(pdev, kb3886_backlight_device);
kb3886_backlight_device->props.max_brightness = machinfo->max_intensity;
kb3886_backlight_device->props.power = FB_BLANK_UNBLANK;
kb3886_backlight_device->props.brightness = machinfo->default_intensity;
backlight_update_status(kb3886_backlight_device);
return 0;
}
static int kb3886bl_remove(struct platform_device *pdev)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
backlight_device_unregister(bd);
return 0;
}
static struct platform_driver kb3886bl_driver = {
.probe = kb3886bl_probe,
.remove = kb3886bl_remove,
.suspend = kb3886bl_suspend,
.resume = kb3886bl_resume,
.driver = {
.name = "kb3886-bl",
},
};
static int __init kb3886_init(void)
{
if (!dmi_check_system(kb3886bl_device_table))
return -ENODEV;
platform_add_devices(devices, ARRAY_SIZE(devices));
return platform_driver_register(&kb3886bl_driver);
}
static void __exit kb3886_exit(void)
{
platform_driver_unregister(&kb3886bl_driver);
}
module_init(kb3886_init);
module_exit(kb3886_exit);
MODULE_AUTHOR("Claudio Nieder <private@claudio.ch>");
MODULE_DESCRIPTION("Tabletkiosk Sahara Touch-iT Backlight Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("dmi:*:svnSDV:pniTouchT201:*");

View File

@@ -0,0 +1,279 @@
/*
* LCD Lowlevel Control Abstraction
*
* Copyright (C) 2003,2004 Hewlett-Packard Company
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/lcd.h>
#include <linux/notifier.h>
#include <linux/ctype.h>
#include <linux/err.h>
#include <linux/fb.h>
#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
defined(CONFIG_LCD_CLASS_DEVICE_MODULE))
/* This callback gets called when something important happens inside a
* framebuffer driver. We're looking if that important event is blanking,
* and if it is, we're switching lcd power as well ...
*/
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data)
{
struct lcd_device *ld;
struct fb_event *evdata = data;
/* If we aren't interested in this event, skip it immediately ... */
switch (event) {
case FB_EVENT_BLANK:
case FB_EVENT_MODE_CHANGE:
case FB_EVENT_MODE_CHANGE_ALL:
break;
default:
return 0;
}
ld = container_of(self, struct lcd_device, fb_notif);
if (!ld->ops)
return 0;
mutex_lock(&ld->ops_lock);
if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) {
if (event == FB_EVENT_BLANK) {
if (ld->ops->set_power)
ld->ops->set_power(ld, *(int *)evdata->data);
} else {
if (ld->ops->set_mode)
ld->ops->set_mode(ld, evdata->data);
}
}
mutex_unlock(&ld->ops_lock);
return 0;
}
static int lcd_register_fb(struct lcd_device *ld)
{
memset(&ld->fb_notif, 0, sizeof(ld->fb_notif));
ld->fb_notif.notifier_call = fb_notifier_callback;
return fb_register_client(&ld->fb_notif);
}
static void lcd_unregister_fb(struct lcd_device *ld)
{
fb_unregister_client(&ld->fb_notif);
}
#else
static int lcd_register_fb(struct lcd_device *ld)
{
return 0;
}
static inline void lcd_unregister_fb(struct lcd_device *ld)
{
}
#endif /* CONFIG_FB */
static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr,
char *buf)
{
int rc;
struct lcd_device *ld = to_lcd_device(dev);
mutex_lock(&ld->ops_lock);
if (ld->ops && ld->ops->get_power)
rc = sprintf(buf, "%d\n", ld->ops->get_power(ld));
else
rc = -ENXIO;
mutex_unlock(&ld->ops_lock);
return rc;
}
static ssize_t lcd_store_power(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int rc = -ENXIO;
char *endp;
struct lcd_device *ld = to_lcd_device(dev);
int power = simple_strtoul(buf, &endp, 0);
size_t size = endp - buf;
if (*endp && isspace(*endp))
size++;
if (size != count)
return -EINVAL;
mutex_lock(&ld->ops_lock);
if (ld->ops && ld->ops->set_power) {
pr_debug("lcd: set power to %d\n", power);
ld->ops->set_power(ld, power);
rc = count;
}
mutex_unlock(&ld->ops_lock);
return rc;
}
static ssize_t lcd_show_contrast(struct device *dev,
struct device_attribute *attr, char *buf)
{
int rc = -ENXIO;
struct lcd_device *ld = to_lcd_device(dev);
mutex_lock(&ld->ops_lock);
if (ld->ops && ld->ops->get_contrast)
rc = sprintf(buf, "%d\n", ld->ops->get_contrast(ld));
mutex_unlock(&ld->ops_lock);
return rc;
}
static ssize_t lcd_store_contrast(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int rc = -ENXIO;
char *endp;
struct lcd_device *ld = to_lcd_device(dev);
int contrast = simple_strtoul(buf, &endp, 0);
size_t size = endp - buf;
if (*endp && isspace(*endp))
size++;
if (size != count)
return -EINVAL;
mutex_lock(&ld->ops_lock);
if (ld->ops && ld->ops->set_contrast) {
pr_debug("lcd: set contrast to %d\n", contrast);
ld->ops->set_contrast(ld, contrast);
rc = count;
}
mutex_unlock(&ld->ops_lock);
return rc;
}
static ssize_t lcd_show_max_contrast(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lcd_device *ld = to_lcd_device(dev);
return sprintf(buf, "%d\n", ld->props.max_contrast);
}
static struct class *lcd_class;
static void lcd_device_release(struct device *dev)
{
struct lcd_device *ld = to_lcd_device(dev);
kfree(ld);
}
static struct device_attribute lcd_device_attributes[] = {
__ATTR(lcd_power, 0644, lcd_show_power, lcd_store_power),
__ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
__ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
__ATTR_NULL,
};
/**
* lcd_device_register - register a new object of lcd_device class.
* @name: the name of the new object(must be the same as the name of the
* respective framebuffer device).
* @devdata: an optional pointer to be stored in the device. The
* methods may retrieve it by using lcd_get_data(ld).
* @ops: the lcd operations structure.
*
* Creates and registers a new lcd device. Returns either an ERR_PTR()
* or a pointer to the newly allocated device.
*/
struct lcd_device *lcd_device_register(const char *name, struct device *parent,
void *devdata, struct lcd_ops *ops)
{
struct lcd_device *new_ld;
int rc;
pr_debug("lcd_device_register: name=%s\n", name);
new_ld = kzalloc(sizeof(struct lcd_device), GFP_KERNEL);
if (!new_ld)
return ERR_PTR(-ENOMEM);
mutex_init(&new_ld->ops_lock);
mutex_init(&new_ld->update_lock);
new_ld->dev.class = lcd_class;
new_ld->dev.parent = parent;
new_ld->dev.release = lcd_device_release;
dev_set_name(&new_ld->dev, name);
dev_set_drvdata(&new_ld->dev, devdata);
rc = device_register(&new_ld->dev);
if (rc) {
kfree(new_ld);
return ERR_PTR(rc);
}
rc = lcd_register_fb(new_ld);
if (rc) {
device_unregister(&new_ld->dev);
return ERR_PTR(rc);
}
new_ld->ops = ops;
return new_ld;
}
EXPORT_SYMBOL(lcd_device_register);
/**
* lcd_device_unregister - unregisters a object of lcd_device class.
* @ld: the lcd device object to be unregistered and freed.
*
* Unregisters a previously registered via lcd_device_register object.
*/
void lcd_device_unregister(struct lcd_device *ld)
{
if (!ld)
return;
mutex_lock(&ld->ops_lock);
ld->ops = NULL;
mutex_unlock(&ld->ops_lock);
lcd_unregister_fb(ld);
device_unregister(&ld->dev);
}
EXPORT_SYMBOL(lcd_device_unregister);
static void __exit lcd_class_exit(void)
{
class_destroy(lcd_class);
}
static int __init lcd_class_init(void)
{
lcd_class = class_create(THIS_MODULE, "lcd");
if (IS_ERR(lcd_class)) {
printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
PTR_ERR(lcd_class));
return PTR_ERR(lcd_class);
}
lcd_class->dev_attrs = lcd_device_attributes;
return 0;
}
/*
* if this is compiled into the kernel, we need to ensure that the
* class is registered before users of the class try to register lcd's
*/
postcore_initcall(lcd_class_init);
module_exit(lcd_class_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>");
MODULE_DESCRIPTION("LCD Lowlevel Control Abstraction");

View File

@@ -0,0 +1,242 @@
/*
* lms283gf05.c -- support for Samsung LMS283GF05 LCD
*
* Copyright (c) 2009 Marek Vasut <marek.vasut@gmail.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.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/lcd.h>
#include <linux/spi/spi.h>
#include <linux/spi/lms283gf05.h>
struct lms283gf05_state {
struct spi_device *spi;
struct lcd_device *ld;
};
struct lms283gf05_seq {
unsigned char reg;
unsigned short value;
unsigned char delay;
};
/* Magic sequences supplied by manufacturer, for details refer to datasheet */
static struct lms283gf05_seq disp_initseq[] = {
/* REG, VALUE, DELAY */
{ 0x07, 0x0000, 0 },
{ 0x13, 0x0000, 10 },
{ 0x11, 0x3004, 0 },
{ 0x14, 0x200F, 0 },
{ 0x10, 0x1a20, 0 },
{ 0x13, 0x0040, 50 },
{ 0x13, 0x0060, 0 },
{ 0x13, 0x0070, 200 },
{ 0x01, 0x0127, 0 },
{ 0x02, 0x0700, 0 },
{ 0x03, 0x1030, 0 },
{ 0x08, 0x0208, 0 },
{ 0x0B, 0x0620, 0 },
{ 0x0C, 0x0110, 0 },
{ 0x30, 0x0120, 0 },
{ 0x31, 0x0127, 0 },
{ 0x32, 0x0000, 0 },
{ 0x33, 0x0503, 0 },
{ 0x34, 0x0727, 0 },
{ 0x35, 0x0124, 0 },
{ 0x36, 0x0706, 0 },
{ 0x37, 0x0701, 0 },
{ 0x38, 0x0F00, 0 },
{ 0x39, 0x0F00, 0 },
{ 0x40, 0x0000, 0 },
{ 0x41, 0x0000, 0 },
{ 0x42, 0x013f, 0 },
{ 0x43, 0x0000, 0 },
{ 0x44, 0x013f, 0 },
{ 0x45, 0x0000, 0 },
{ 0x46, 0xef00, 0 },
{ 0x47, 0x013f, 0 },
{ 0x48, 0x0000, 0 },
{ 0x07, 0x0015, 30 },
{ 0x07, 0x0017, 0 },
{ 0x20, 0x0000, 0 },
{ 0x21, 0x0000, 0 },
{ 0x22, 0x0000, 0 }
};
static struct lms283gf05_seq disp_pdwnseq[] = {
{ 0x07, 0x0016, 30 },
{ 0x07, 0x0004, 0 },
{ 0x10, 0x0220, 20 },
{ 0x13, 0x0060, 50 },
{ 0x13, 0x0040, 50 },
{ 0x13, 0x0000, 0 },
{ 0x10, 0x0000, 0 }
};
static void lms283gf05_reset(unsigned long gpio, bool inverted)
{
gpio_set_value(gpio, !inverted);
mdelay(100);
gpio_set_value(gpio, inverted);
mdelay(20);
gpio_set_value(gpio, !inverted);
mdelay(20);
}
static void lms283gf05_toggle(struct spi_device *spi,
struct lms283gf05_seq *seq, int sz)
{
char buf[3];
int i;
for (i = 0; i < sz; i++) {
buf[0] = 0x74;
buf[1] = 0x00;
buf[2] = seq[i].reg;
spi_write(spi, buf, 3);
buf[0] = 0x76;
buf[1] = seq[i].value >> 8;
buf[2] = seq[i].value & 0xff;
spi_write(spi, buf, 3);
mdelay(seq[i].delay);
}
}
static int lms283gf05_power_set(struct lcd_device *ld, int power)
{
struct lms283gf05_state *st = lcd_get_data(ld);
struct spi_device *spi = st->spi;
struct lms283gf05_pdata *pdata = spi->dev.platform_data;
if (power) {
if (pdata)
lms283gf05_reset(pdata->reset_gpio,
pdata->reset_inverted);
lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq));
} else {
lms283gf05_toggle(spi, disp_pdwnseq, ARRAY_SIZE(disp_pdwnseq));
if (pdata)
gpio_set_value(pdata->reset_gpio,
pdata->reset_inverted);
}
return 0;
}
static struct lcd_ops lms_ops = {
.set_power = lms283gf05_power_set,
.get_power = NULL,
};
static int __devinit lms283gf05_probe(struct spi_device *spi)
{
struct lms283gf05_state *st;
struct lms283gf05_pdata *pdata = spi->dev.platform_data;
struct lcd_device *ld;
int ret = 0;
if (pdata != NULL) {
ret = gpio_request(pdata->reset_gpio, "LMS285GF05 RESET");
if (ret)
return ret;
ret = gpio_direction_output(pdata->reset_gpio,
!pdata->reset_inverted);
if (ret)
goto err;
}
st = kzalloc(sizeof(struct lms283gf05_state), GFP_KERNEL);
if (st == NULL) {
dev_err(&spi->dev, "No memory for device state\n");
ret = -ENOMEM;
goto err;
}
ld = lcd_device_register("lms283gf05", &spi->dev, st, &lms_ops);
if (IS_ERR(ld)) {
ret = PTR_ERR(ld);
goto err2;
}
st->spi = spi;
st->ld = ld;
dev_set_drvdata(&spi->dev, st);
/* kick in the LCD */
if (pdata)
lms283gf05_reset(pdata->reset_gpio, pdata->reset_inverted);
lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq));
return 0;
err2:
kfree(st);
err:
if (pdata != NULL)
gpio_free(pdata->reset_gpio);
return ret;
}
static int __devexit lms283gf05_remove(struct spi_device *spi)
{
struct lms283gf05_state *st = dev_get_drvdata(&spi->dev);
struct lms283gf05_pdata *pdata = st->spi->dev.platform_data;
lcd_device_unregister(st->ld);
if (pdata != NULL)
gpio_free(pdata->reset_gpio);
kfree(st);
return 0;
}
static struct spi_driver lms283gf05_driver = {
.driver = {
.name = "lms283gf05",
.owner = THIS_MODULE,
},
.probe = lms283gf05_probe,
.remove = __devexit_p(lms283gf05_remove),
};
static __init int lms283gf05_init(void)
{
return spi_register_driver(&lms283gf05_driver);
}
static __exit void lms283gf05_exit(void)
{
spi_unregister_driver(&lms283gf05_driver);
}
module_init(lms283gf05_init);
module_exit(lms283gf05_exit);
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
MODULE_DESCRIPTION("LCD283GF05 LCD");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,247 @@
/*
* Backlight control code for Sharp Zaurus SL-5500
*
* Copyright 2005 John Lenz <lenz@cs.wisc.edu>
* Maintainer: Pavel Machek <pavel@suse.cz> (unless John wants to :-)
* GPL v2
*
* This driver assumes single CPU. That's okay, because collie is
* slightly old hardware, and noone is going to retrofit second CPU to
* old PDA.
*/
/* LCD power functions */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <asm/hardware/locomo.h>
#include <asm/irq.h>
#include <asm/mach/sharpsl_param.h>
#include <asm/mach-types.h>
#include "../../../arch/arm/mach-sa1100/generic.h"
static struct backlight_device *locomolcd_bl_device;
static struct locomo_dev *locomolcd_dev;
static unsigned long locomolcd_flags;
#define LOCOMOLCD_SUSPENDED 0x01
static void locomolcd_on(int comadj)
{
locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0);
locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 1);
mdelay(2);
locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0);
locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 1);
mdelay(2);
locomo_m62332_senddata(locomolcd_dev, comadj, 0);
mdelay(5);
locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0);
locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 1);
mdelay(10);
/* TFTCRST | CPSOUT=0 | CPSEN */
locomo_writel(0x01, locomolcd_dev->mapbase + LOCOMO_TC);
/* Set CPSD */
locomo_writel(6, locomolcd_dev->mapbase + LOCOMO_CPSD);
/* TFTCRST | CPSOUT=0 | CPSEN */
locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC);
mdelay(10);
locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0);
locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 1);
}
static void locomolcd_off(int comadj)
{
/* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */
locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC);
mdelay(1);
locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0);
mdelay(110);
locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0);
mdelay(700);
/* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */
locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC);
locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0);
locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0);
}
void locomolcd_power(int on)
{
int comadj = sharpsl_param.comadj;
unsigned long flags;
local_irq_save(flags);
if (!locomolcd_dev) {
local_irq_restore(flags);
return;
}
/* read comadj */
if (comadj == -1 && machine_is_collie())
comadj = 128;
if (comadj == -1 && machine_is_poodle())
comadj = 118;
if (on)
locomolcd_on(comadj);
else
locomolcd_off(comadj);
local_irq_restore(flags);
}
EXPORT_SYMBOL(locomolcd_power);
static int current_intensity;
static int locomolcd_set_intensity(struct backlight_device *bd)
{
int intensity = bd->props.brightness;
if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (locomolcd_flags & LOCOMOLCD_SUSPENDED)
intensity = 0;
switch (intensity) {
/* AC and non-AC are handled differently, but produce same results in sharp code? */
case 0: locomo_frontlight_set(locomolcd_dev, 0, 0, 161); break;
case 1: locomo_frontlight_set(locomolcd_dev, 117, 0, 161); break;
case 2: locomo_frontlight_set(locomolcd_dev, 163, 0, 148); break;
case 3: locomo_frontlight_set(locomolcd_dev, 194, 0, 161); break;
case 4: locomo_frontlight_set(locomolcd_dev, 194, 1, 161); break;
default:
return -ENODEV;
}
current_intensity = intensity;
return 0;
}
static int locomolcd_get_intensity(struct backlight_device *bd)
{
return current_intensity;
}
static struct backlight_ops locomobl_data = {
.get_brightness = locomolcd_get_intensity,
.update_status = locomolcd_set_intensity,
};
#ifdef CONFIG_PM
static int locomolcd_suspend(struct locomo_dev *dev, pm_message_t state)
{
locomolcd_flags |= LOCOMOLCD_SUSPENDED;
locomolcd_set_intensity(locomolcd_bl_device);
return 0;
}
static int locomolcd_resume(struct locomo_dev *dev)
{
locomolcd_flags &= ~LOCOMOLCD_SUSPENDED;
locomolcd_set_intensity(locomolcd_bl_device);
return 0;
}
#else
#define locomolcd_suspend NULL
#define locomolcd_resume NULL
#endif
static int locomolcd_probe(struct locomo_dev *ldev)
{
unsigned long flags;
local_irq_save(flags);
locomolcd_dev = ldev;
locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0);
/* the poodle_lcd_power function is called for the first time
* from fs_initcall, which is before locomo is activated.
* We need to recall poodle_lcd_power here*/
if (machine_is_poodle())
locomolcd_power(1);
local_irq_restore(flags);
locomolcd_bl_device = backlight_device_register("locomo-bl", &ldev->dev, NULL, &locomobl_data);
if (IS_ERR (locomolcd_bl_device))
return PTR_ERR (locomolcd_bl_device);
/* Set up frontlight so that screen is readable */
locomolcd_bl_device->props.max_brightness = 4,
locomolcd_bl_device->props.brightness = 2;
locomolcd_set_intensity(locomolcd_bl_device);
return 0;
}
static int locomolcd_remove(struct locomo_dev *dev)
{
unsigned long flags;
locomolcd_bl_device->props.brightness = 0;
locomolcd_bl_device->props.power = 0;
locomolcd_set_intensity(locomolcd_bl_device);
backlight_device_unregister(locomolcd_bl_device);
local_irq_save(flags);
locomolcd_dev = NULL;
local_irq_restore(flags);
return 0;
}
static struct locomo_driver poodle_lcd_driver = {
.drv = {
.name = "locomo-backlight",
},
.devid = LOCOMO_DEVID_BACKLIGHT,
.probe = locomolcd_probe,
.remove = locomolcd_remove,
.suspend = locomolcd_suspend,
.resume = locomolcd_resume,
};
static int __init locomolcd_init(void)
{
int ret = locomo_driver_register(&poodle_lcd_driver);
if (ret)
return ret;
#ifdef CONFIG_SA1100_COLLIE
sa1100fb_lcd_power = locomolcd_power;
#endif
return 0;
}
static void __exit locomolcd_exit(void)
{
locomo_driver_unregister(&poodle_lcd_driver);
}
module_init(locomolcd_init);
module_exit(locomolcd_exit);
MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@suse.cz>");
MODULE_DESCRIPTION("Collie LCD driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,331 @@
/*
* Power control for Samsung LTV350QV Quarter VGA LCD Panel
*
* Copyright (C) 2006, 2007 Atmel Corporation
*
* 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.
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/lcd.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include "ltv350qv.h"
#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
struct ltv350qv {
struct spi_device *spi;
u8 *buffer;
int power;
struct lcd_device *ld;
};
/*
* The power-on and power-off sequences are taken from the
* LTV350QV-F04 data sheet from Samsung. The register definitions are
* taken from the S6F2002 command list also from Samsung. Both
* documents are distributed with the AVR32 Linux BSP CD from Atmel.
*
* There's still some voodoo going on here, but it's a lot better than
* in the first incarnation of the driver where all we had was the raw
* numbers from the initialization sequence.
*/
static int ltv350qv_write_reg(struct ltv350qv *lcd, u8 reg, u16 val)
{
struct spi_message msg;
struct spi_transfer index_xfer = {
.len = 3,
.cs_change = 1,
};
struct spi_transfer value_xfer = {
.len = 3,
};
spi_message_init(&msg);
/* register index */
lcd->buffer[0] = LTV_OPC_INDEX;
lcd->buffer[1] = 0x00;
lcd->buffer[2] = reg & 0x7f;
index_xfer.tx_buf = lcd->buffer;
spi_message_add_tail(&index_xfer, &msg);
/* register value */
lcd->buffer[4] = LTV_OPC_DATA;
lcd->buffer[5] = val >> 8;
lcd->buffer[6] = val;
value_xfer.tx_buf = lcd->buffer + 4;
spi_message_add_tail(&value_xfer, &msg);
return spi_sync(lcd->spi, &msg);
}
/* The comments are taken straight from the data sheet */
static int ltv350qv_power_on(struct ltv350qv *lcd)
{
int ret;
/* Power On Reset Display off State */
if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000))
goto err;
msleep(15);
/* Power Setting Function 1 */
if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE))
goto err;
if (ltv350qv_write_reg(lcd, LTV_PWRCTL2, LTV_VCOML_ENABLE))
goto err_power1;
/* Power Setting Function 2 */
if (ltv350qv_write_reg(lcd, LTV_PWRCTL1,
LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5)
| LTV_SUPPLY_CURRENT(5)))
goto err_power2;
msleep(55);
/* Instruction Setting */
ret = ltv350qv_write_reg(lcd, LTV_IFCTL,
LTV_NMD | LTV_REV | LTV_NL(0x1d));
ret |= ltv350qv_write_reg(lcd, LTV_DATACTL,
LTV_DS_SAME | LTV_CHS_480
| LTV_DF_RGB | LTV_RGB_BGR);
ret |= ltv350qv_write_reg(lcd, LTV_ENTRY_MODE,
LTV_VSPL_ACTIVE_LOW
| LTV_HSPL_ACTIVE_LOW
| LTV_DPL_SAMPLE_RISING
| LTV_EPL_ACTIVE_LOW
| LTV_SS_RIGHT_TO_LEFT);
ret |= ltv350qv_write_reg(lcd, LTV_GATECTL1, LTV_CLW(3));
ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
LTV_NW_INV_1LINE | LTV_FWI(3));
ret |= ltv350qv_write_reg(lcd, LTV_VBP, 0x000a);
ret |= ltv350qv_write_reg(lcd, LTV_HBP, 0x0021);
ret |= ltv350qv_write_reg(lcd, LTV_SOTCTL, LTV_SDT(3) | LTV_EQ(0));
ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(0), 0x0103);
ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(1), 0x0301);
ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(2), 0x1f0f);
ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(3), 0x1f0f);
ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(4), 0x0707);
ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(5), 0x0307);
ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(6), 0x0707);
ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(7), 0x0000);
ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(8), 0x0004);
ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(9), 0x0000);
if (ret)
goto err_settings;
/* Wait more than 2 frames */
msleep(20);
/* Display On Sequence */
ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1,
LTV_VCOM_DISABLE | LTV_VCOMOUT_ENABLE
| LTV_POWER_ON | LTV_DRIVE_CURRENT(5)
| LTV_SUPPLY_CURRENT(5));
ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
LTV_NW_INV_1LINE | LTV_DSC | LTV_FWI(3));
if (ret)
goto err_disp_on;
/* Display should now be ON. Phew. */
return 0;
err_disp_on:
/*
* Try to recover. Error handling probably isn't very useful
* at this point, just make a best effort to switch the panel
* off.
*/
ltv350qv_write_reg(lcd, LTV_PWRCTL1,
LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5)
| LTV_SUPPLY_CURRENT(5));
ltv350qv_write_reg(lcd, LTV_GATECTL2,
LTV_NW_INV_1LINE | LTV_FWI(3));
err_settings:
err_power2:
err_power1:
ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
msleep(1);
err:
ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
return -EIO;
}
static int ltv350qv_power_off(struct ltv350qv *lcd)
{
int ret;
/* Display Off Sequence */
ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1,
LTV_VCOM_DISABLE
| LTV_DRIVE_CURRENT(5)
| LTV_SUPPLY_CURRENT(5));
ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
LTV_NW_INV_1LINE | LTV_FWI(3));
/* Power down setting 1 */
ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
/* Wait at least 1 ms */
msleep(1);
/* Power down setting 2 */
ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
/*
* No point in trying to recover here. If we can't switch the
* panel off, what are we supposed to do other than inform the
* user about the failure?
*/
if (ret)
return -EIO;
/* Display power should now be OFF */
return 0;
}
static int ltv350qv_power(struct ltv350qv *lcd, int power)
{
int ret = 0;
if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
ret = ltv350qv_power_on(lcd);
else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
ret = ltv350qv_power_off(lcd);
if (!ret)
lcd->power = power;
return ret;
}
static int ltv350qv_set_power(struct lcd_device *ld, int power)
{
struct ltv350qv *lcd = lcd_get_data(ld);
return ltv350qv_power(lcd, power);
}
static int ltv350qv_get_power(struct lcd_device *ld)
{
struct ltv350qv *lcd = lcd_get_data(ld);
return lcd->power;
}
static struct lcd_ops ltv_ops = {
.get_power = ltv350qv_get_power,
.set_power = ltv350qv_set_power,
};
static int __devinit ltv350qv_probe(struct spi_device *spi)
{
struct ltv350qv *lcd;
struct lcd_device *ld;
int ret;
lcd = kzalloc(sizeof(struct ltv350qv), GFP_KERNEL);
if (!lcd)
return -ENOMEM;
lcd->spi = spi;
lcd->power = FB_BLANK_POWERDOWN;
lcd->buffer = kzalloc(8, GFP_KERNEL);
ld = lcd_device_register("ltv350qv", &spi->dev, lcd, &ltv_ops);
if (IS_ERR(ld)) {
ret = PTR_ERR(ld);
goto out_free_lcd;
}
lcd->ld = ld;
ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK);
if (ret)
goto out_unregister;
dev_set_drvdata(&spi->dev, lcd);
return 0;
out_unregister:
lcd_device_unregister(ld);
out_free_lcd:
kfree(lcd);
return ret;
}
static int __devexit ltv350qv_remove(struct spi_device *spi)
{
struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
lcd_device_unregister(lcd->ld);
kfree(lcd);
return 0;
}
#ifdef CONFIG_PM
static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state)
{
struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
return ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
}
static int ltv350qv_resume(struct spi_device *spi)
{
struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
return ltv350qv_power(lcd, FB_BLANK_UNBLANK);
}
#else
#define ltv350qv_suspend NULL
#define ltv350qv_resume NULL
#endif
/* Power down all displays on reboot, poweroff or halt */
static void ltv350qv_shutdown(struct spi_device *spi)
{
struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
}
static struct spi_driver ltv350qv_driver = {
.driver = {
.name = "ltv350qv",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = ltv350qv_probe,
.remove = __devexit_p(ltv350qv_remove),
.shutdown = ltv350qv_shutdown,
.suspend = ltv350qv_suspend,
.resume = ltv350qv_resume,
};
static int __init ltv350qv_init(void)
{
return spi_register_driver(&ltv350qv_driver);
}
static void __exit ltv350qv_exit(void)
{
spi_unregister_driver(&ltv350qv_driver);
}
module_init(ltv350qv_init);
module_exit(ltv350qv_exit);
MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:ltv350qv");

View File

@@ -0,0 +1,95 @@
/*
* Register definitions for Samsung LTV350QV Quarter VGA LCD Panel
*
* Copyright (C) 2006, 2007 Atmel Corporation
*
* 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 __LTV350QV_H
#define __LTV350QV_H
#define LTV_OPC_INDEX 0x74
#define LTV_OPC_DATA 0x76
#define LTV_ID 0x00 /* ID Read */
#define LTV_IFCTL 0x01 /* Display Interface Control */
#define LTV_DATACTL 0x02 /* Display Data Control */
#define LTV_ENTRY_MODE 0x03 /* Entry Mode */
#define LTV_GATECTL1 0x04 /* Gate Control 1 */
#define LTV_GATECTL2 0x05 /* Gate Control 2 */
#define LTV_VBP 0x06 /* Vertical Back Porch */
#define LTV_HBP 0x07 /* Horizontal Back Porch */
#define LTV_SOTCTL 0x08 /* Source Output Timing Control */
#define LTV_PWRCTL1 0x09 /* Power Control 1 */
#define LTV_PWRCTL2 0x0a /* Power Control 2 */
#define LTV_GAMMA(x) (0x10 + (x)) /* Gamma control */
/* Bit definitions for LTV_IFCTL */
#define LTV_IM (1 << 15)
#define LTV_NMD (1 << 14)
#define LTV_SSMD (1 << 13)
#define LTV_REV (1 << 7)
#define LTV_NL(x) (((x) & 0x001f) << 0)
/* Bit definitions for LTV_DATACTL */
#define LTV_DS_SAME (0 << 12)
#define LTV_DS_D_TO_S (1 << 12)
#define LTV_DS_S_TO_D (2 << 12)
#define LTV_CHS_384 (0 << 9)
#define LTV_CHS_480 (1 << 9)
#define LTV_CHS_492 (2 << 9)
#define LTV_DF_RGB (0 << 6)
#define LTV_DF_RGBX (1 << 6)
#define LTV_DF_XRGB (2 << 6)
#define LTV_RGB_RGB (0 << 2)
#define LTV_RGB_BGR (1 << 2)
#define LTV_RGB_GRB (2 << 2)
#define LTV_RGB_RBG (3 << 2)
/* Bit definitions for LTV_ENTRY_MODE */
#define LTV_VSPL_ACTIVE_LOW (0 << 15)
#define LTV_VSPL_ACTIVE_HIGH (1 << 15)
#define LTV_HSPL_ACTIVE_LOW (0 << 14)
#define LTV_HSPL_ACTIVE_HIGH (1 << 14)
#define LTV_DPL_SAMPLE_RISING (0 << 13)
#define LTV_DPL_SAMPLE_FALLING (1 << 13)
#define LTV_EPL_ACTIVE_LOW (0 << 12)
#define LTV_EPL_ACTIVE_HIGH (1 << 12)
#define LTV_SS_LEFT_TO_RIGHT (0 << 8)
#define LTV_SS_RIGHT_TO_LEFT (1 << 8)
#define LTV_STB (1 << 1)
/* Bit definitions for LTV_GATECTL1 */
#define LTV_CLW(x) (((x) & 0x0007) << 12)
#define LTV_GAON (1 << 5)
#define LTV_SDR (1 << 3)
/* Bit definitions for LTV_GATECTL2 */
#define LTV_NW_INV_FRAME (0 << 14)
#define LTV_NW_INV_1LINE (1 << 14)
#define LTV_NW_INV_2LINE (2 << 14)
#define LTV_DSC (1 << 12)
#define LTV_GIF (1 << 8)
#define LTV_FHN (1 << 7)
#define LTV_FTI(x) (((x) & 0x0003) << 4)
#define LTV_FWI(x) (((x) & 0x0003) << 0)
/* Bit definitions for LTV_SOTCTL */
#define LTV_SDT(x) (((x) & 0x0007) << 10)
#define LTV_EQ(x) (((x) & 0x0007) << 2)
/* Bit definitions for LTV_PWRCTL1 */
#define LTV_VCOM_DISABLE (1 << 14)
#define LTV_VCOMOUT_ENABLE (1 << 11)
#define LTV_POWER_ON (1 << 9)
#define LTV_DRIVE_CURRENT(x) (((x) & 0x0007) << 4) /* 0=off, 5=max */
#define LTV_SUPPLY_CURRENT(x) (((x) & 0x0007) << 0) /* 0=off, 5=max */
/* Bit definitions for LTV_PWRCTL2 */
#define LTV_VCOML_ENABLE (1 << 13)
#define LTV_VCOML_VOLTAGE(x) (((x) & 0x001f) << 8) /* 0=1V, 31=-1V */
#define LTV_VCOMH_VOLTAGE(x) (((x) & 0x001f) << 0) /* 0=3V, 31=4.5V */
#endif /* __LTV350QV_H */

View File

@@ -0,0 +1,333 @@
/*
* Backlight Driver for Nvidia 8600 in Macbook Pro
*
* Copyright (c) Red Hat <mjg@redhat.com>
* Based on code from Pommed:
* Copyright (C) 2006 Nicolas Boichat <nicolas @boichat.ch>
* Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org>
* Copyright (C) 2007 Julien BLACHE <jb@jblache.org>
*
* 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 triggers SMIs which cause the firmware to change the
* backlight brightness. This is icky in many ways, but it's impractical to
* get at the firmware code in order to figure out what it's actually doing.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/backlight.h>
#include <linux/err.h>
#include <linux/dmi.h>
#include <linux/io.h>
static struct backlight_device *mbp_backlight_device;
/* Structure to be passed to the DMI_MATCH function. */
struct dmi_match_data {
/* I/O resource to allocate. */
unsigned long iostart;
unsigned long iolen;
/* Backlight operations structure. */
struct backlight_ops backlight_ops;
};
/* Module parameters. */
static int debug;
module_param_named(debug, debug, int, 0644);
MODULE_PARM_DESC(debug, "Set to one to enable debugging messages.");
/*
* Implementation for MacBooks with Intel chipset.
*/
static int intel_chipset_send_intensity(struct backlight_device *bd)
{
int intensity = bd->props.brightness;
if (debug)
printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n",
intensity);
outb(0x04 | (intensity << 4), 0xb3);
outb(0xbf, 0xb2);
return 0;
}
static int intel_chipset_get_intensity(struct backlight_device *bd)
{
int intensity;
outb(0x03, 0xb3);
outb(0xbf, 0xb2);
intensity = inb(0xb3) >> 4;
if (debug)
printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n",
intensity);
return intensity;
}
static const struct dmi_match_data intel_chipset_data = {
.iostart = 0xb2,
.iolen = 2,
.backlight_ops = {
.options = BL_CORE_SUSPENDRESUME,
.get_brightness = intel_chipset_get_intensity,
.update_status = intel_chipset_send_intensity,
}
};
/*
* Implementation for MacBooks with Nvidia chipset.
*/
static int nvidia_chipset_send_intensity(struct backlight_device *bd)
{
int intensity = bd->props.brightness;
if (debug)
printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n",
intensity);
outb(0x04 | (intensity << 4), 0x52f);
outb(0xbf, 0x52e);
return 0;
}
static int nvidia_chipset_get_intensity(struct backlight_device *bd)
{
int intensity;
outb(0x03, 0x52f);
outb(0xbf, 0x52e);
intensity = inb(0x52f) >> 4;
if (debug)
printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n",
intensity);
return intensity;
}
static const struct dmi_match_data nvidia_chipset_data = {
.iostart = 0x52e,
.iolen = 2,
.backlight_ops = {
.options = BL_CORE_SUSPENDRESUME,
.get_brightness = nvidia_chipset_get_intensity,
.update_status = nvidia_chipset_send_intensity
}
};
/*
* DMI matching.
*/
static /* const */ struct dmi_match_data *driver_data;
static int mbp_dmi_match(const struct dmi_system_id *id)
{
driver_data = id->driver_data;
printk(KERN_INFO "mbp_nvidia_bl: %s detected\n", id->ident);
return 1;
}
static const struct dmi_system_id __initdata mbp_device_table[] = {
{
.callback = mbp_dmi_match,
.ident = "MacBook 1,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBook 2,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBook 3,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook3,1"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBook 4,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,1"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBook 4,2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,2"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookPro 3,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookPro 3,2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookPro 4,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookAir 1,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir1,1"),
},
.driver_data = (void *)&intel_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBook 5,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,1"),
},
.driver_data = (void *)&nvidia_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBook 5,2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,2"),
},
.driver_data = (void *)&nvidia_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookAir 2,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2,1"),
},
.driver_data = (void *)&nvidia_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookPro 5,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"),
},
.driver_data = (void *)&nvidia_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookPro 5,2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,2"),
},
.driver_data = (void *)&nvidia_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookPro 5,5",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,5"),
},
.driver_data = (void *)&nvidia_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookAir 3,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"),
},
.driver_data = (void *)&nvidia_chipset_data,
},
{
.callback = mbp_dmi_match,
.ident = "MacBookAir 3,2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"),
},
.driver_data = (void *)&nvidia_chipset_data,
},
{ }
};
static int __init mbp_init(void)
{
if (!dmi_check_system(mbp_device_table))
return -ENODEV;
if (!request_region(driver_data->iostart, driver_data->iolen,
"Macbook Pro backlight"))
return -ENXIO;
mbp_backlight_device = backlight_device_register("mbp_backlight",
NULL, NULL, &driver_data->backlight_ops);
if (IS_ERR(mbp_backlight_device)) {
release_region(driver_data->iostart, driver_data->iolen);
return PTR_ERR(mbp_backlight_device);
}
mbp_backlight_device->props.max_brightness = 15;
mbp_backlight_device->props.brightness =
driver_data->backlight_ops.get_brightness(mbp_backlight_device);
backlight_update_status(mbp_backlight_device);
return 0;
}
static void __exit mbp_exit(void)
{
backlight_device_unregister(mbp_backlight_device);
release_region(driver_data->iostart, driver_data->iolen);
}
module_init(mbp_init);
module_exit(mbp_exit);
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(dmi, mbp_device_table);

View File

@@ -0,0 +1,210 @@
/*
* Backlight driver for OMAP based boards.
*
* Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
*
* This package 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 package 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 package; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <mach/hardware.h>
#include <mach/board.h>
#include <mach/mux.h>
#define OMAPBL_MAX_INTENSITY 0xff
struct omap_backlight {
int powermode;
int current_intensity;
struct device *dev;
struct omap_backlight_config *pdata;
};
static void inline omapbl_send_intensity(int intensity)
{
omap_writeb(intensity, OMAP_PWL_ENABLE);
}
static void inline omapbl_send_enable(int enable)
{
omap_writeb(enable, OMAP_PWL_CLK_ENABLE);
}
static void omapbl_blank(struct omap_backlight *bl, int mode)
{
if (bl->pdata->set_power)
bl->pdata->set_power(bl->dev, mode);
switch (mode) {
case FB_BLANK_NORMAL:
case FB_BLANK_VSYNC_SUSPEND:
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_POWERDOWN:
omapbl_send_intensity(0);
omapbl_send_enable(0);
break;
case FB_BLANK_UNBLANK:
omapbl_send_intensity(bl->current_intensity);
omapbl_send_enable(1);
break;
}
}
#ifdef CONFIG_PM
static int omapbl_suspend(struct platform_device *pdev, pm_message_t state)
{
struct backlight_device *dev = platform_get_drvdata(pdev);
struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
omapbl_blank(bl, FB_BLANK_POWERDOWN);
return 0;
}
static int omapbl_resume(struct platform_device *pdev)
{
struct backlight_device *dev = platform_get_drvdata(pdev);
struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
omapbl_blank(bl, bl->powermode);
return 0;
}
#else
#define omapbl_suspend NULL
#define omapbl_resume NULL
#endif
static int omapbl_set_power(struct backlight_device *dev, int state)
{
struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
omapbl_blank(bl, state);
bl->powermode = state;
return 0;
}
static int omapbl_update_status(struct backlight_device *dev)
{
struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
if (bl->current_intensity != dev->props.brightness) {
if (bl->powermode == FB_BLANK_UNBLANK)
omapbl_send_intensity(dev->props.brightness);
bl->current_intensity = dev->props.brightness;
}
if (dev->props.fb_blank != bl->powermode)
omapbl_set_power(dev, dev->props.fb_blank);
return 0;
}
static int omapbl_get_intensity(struct backlight_device *dev)
{
struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
return bl->current_intensity;
}
static struct backlight_ops omapbl_ops = {
.get_brightness = omapbl_get_intensity,
.update_status = omapbl_update_status,
};
static int omapbl_probe(struct platform_device *pdev)
{
struct backlight_device *dev;
struct omap_backlight *bl;
struct omap_backlight_config *pdata = pdev->dev.platform_data;
if (!pdata)
return -ENXIO;
omapbl_ops.check_fb = pdata->check_fb;
bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL);
if (unlikely(!bl))
return -ENOMEM;
dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops);
if (IS_ERR(dev)) {
kfree(bl);
return PTR_ERR(dev);
}
bl->powermode = FB_BLANK_POWERDOWN;
bl->current_intensity = 0;
bl->pdata = pdata;
bl->dev = &pdev->dev;
platform_set_drvdata(pdev, dev);
omap_cfg_reg(PWL); /* Conflicts with UART3 */
dev->props.fb_blank = FB_BLANK_UNBLANK;
dev->props.max_brightness = OMAPBL_MAX_INTENSITY;
dev->props.brightness = pdata->default_intensity;
omapbl_update_status(dev);
printk(KERN_INFO "OMAP LCD backlight initialised\n");
return 0;
}
static int omapbl_remove(struct platform_device *pdev)
{
struct backlight_device *dev = platform_get_drvdata(pdev);
struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
backlight_device_unregister(dev);
kfree(bl);
return 0;
}
static struct platform_driver omapbl_driver = {
.probe = omapbl_probe,
.remove = omapbl_remove,
.suspend = omapbl_suspend,
.resume = omapbl_resume,
.driver = {
.name = "omap-bl",
},
};
static int __init omapbl_init(void)
{
return platform_driver_register(&omapbl_driver);
}
static void __exit omapbl_exit(void)
{
platform_driver_unregister(&omapbl_driver);
}
module_init(omapbl_init);
module_exit(omapbl_exit);
MODULE_AUTHOR("Andrzej Zaborowski <balrog@zabor.org>");
MODULE_DESCRIPTION("OMAP LCD Backlight driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,174 @@
/* drivers/video/backlight/platform_lcd.c
*
* Copyright 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Generic platform-device LCD power control interface.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/lcd.h>
#include <video/platform_lcd.h>
struct platform_lcd {
struct device *us;
struct lcd_device *lcd;
struct plat_lcd_data *pdata;
unsigned int power;
unsigned int suspended : 1;
};
static inline struct platform_lcd *to_our_lcd(struct lcd_device *lcd)
{
return lcd_get_data(lcd);
}
static int platform_lcd_get_power(struct lcd_device *lcd)
{
struct platform_lcd *plcd = to_our_lcd(lcd);
return plcd->power;
}
static int platform_lcd_set_power(struct lcd_device *lcd, int power)
{
struct platform_lcd *plcd = to_our_lcd(lcd);
int lcd_power = 1;
if (power == FB_BLANK_POWERDOWN || plcd->suspended)
lcd_power = 0;
plcd->pdata->set_power(plcd->pdata, lcd_power);
plcd->power = power;
return 0;
}
static int platform_lcd_match(struct lcd_device *lcd, struct fb_info *info)
{
struct platform_lcd *plcd = to_our_lcd(lcd);
struct plat_lcd_data *pdata = plcd->pdata;
if (pdata->match_fb)
return pdata->match_fb(pdata, info);
return plcd->us->parent == info->device;
}
static struct lcd_ops platform_lcd_ops = {
.get_power = platform_lcd_get_power,
.set_power = platform_lcd_set_power,
.check_fb = platform_lcd_match,
};
static int __devinit platform_lcd_probe(struct platform_device *pdev)
{
struct plat_lcd_data *pdata;
struct platform_lcd *plcd;
struct device *dev = &pdev->dev;
int err;
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(dev, "no platform data supplied\n");
return -EINVAL;
}
plcd = kzalloc(sizeof(struct platform_lcd), GFP_KERNEL);
if (!plcd) {
dev_err(dev, "no memory for state\n");
return -ENOMEM;
}
plcd->us = dev;
plcd->pdata = pdata;
plcd->lcd = lcd_device_register(dev_name(dev), dev,
plcd, &platform_lcd_ops);
if (IS_ERR(plcd->lcd)) {
dev_err(dev, "cannot register lcd device\n");
err = PTR_ERR(plcd->lcd);
goto err_mem;
}
platform_set_drvdata(pdev, plcd);
platform_lcd_set_power(plcd->lcd, FB_BLANK_NORMAL);
return 0;
err_mem:
kfree(plcd);
return err;
}
static int __devexit platform_lcd_remove(struct platform_device *pdev)
{
struct platform_lcd *plcd = platform_get_drvdata(pdev);
lcd_device_unregister(plcd->lcd);
kfree(plcd);
return 0;
}
#ifdef CONFIG_PM
static int platform_lcd_suspend(struct platform_device *pdev, pm_message_t st)
{
struct platform_lcd *plcd = platform_get_drvdata(pdev);
plcd->suspended = 1;
platform_lcd_set_power(plcd->lcd, plcd->power);
return 0;
}
static int platform_lcd_resume(struct platform_device *pdev)
{
struct platform_lcd *plcd = platform_get_drvdata(pdev);
plcd->suspended = 0;
platform_lcd_set_power(plcd->lcd, plcd->power);
return 0;
}
#else
#define platform_lcd_suspend NULL
#define platform_lcd_resume NULL
#endif
static struct platform_driver platform_lcd_driver = {
.driver = {
.name = "platform-lcd",
.owner = THIS_MODULE,
},
.probe = platform_lcd_probe,
.remove = __devexit_p(platform_lcd_remove),
.suspend = platform_lcd_suspend,
.resume = platform_lcd_resume,
};
static int __init platform_lcd_init(void)
{
return platform_driver_register(&platform_lcd_driver);
}
static void __exit platform_lcd_cleanup(void)
{
platform_driver_unregister(&platform_lcd_driver);
}
module_init(platform_lcd_init);
module_exit(platform_lcd_cleanup);
MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:platform-lcd");

View File

@@ -0,0 +1,148 @@
/*
* Backlight Driver for Frontpath ProGear HX1050+
*
* Copyright (c) 2006 Marcin Juszkiewicz
*
* Based on Progear LCD driver by M Schacht
* <mschacht at alumni dot washington dot edu>
*
* Based on Sharp's Corgi Backlight Driver
* Based on Backlight Driver for HP Jornada 680
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/pci.h>
#define PMU_LPCR 0xB0
#define SB_MPS1 0x61
#define HW_LEVEL_MAX 0x77
#define HW_LEVEL_MIN 0x4f
static struct pci_dev *pmu_dev = NULL;
static struct pci_dev *sb_dev = NULL;
static int progearbl_set_intensity(struct backlight_device *bd)
{
int intensity = bd->props.brightness;
if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
pci_write_config_byte(pmu_dev, PMU_LPCR, intensity + HW_LEVEL_MIN);
return 0;
}
static int progearbl_get_intensity(struct backlight_device *bd)
{
u8 intensity;
pci_read_config_byte(pmu_dev, PMU_LPCR, &intensity);
return intensity - HW_LEVEL_MIN;
}
static struct backlight_ops progearbl_ops = {
.get_brightness = progearbl_get_intensity,
.update_status = progearbl_set_intensity,
};
static int progearbl_probe(struct platform_device *pdev)
{
u8 temp;
struct backlight_device *progear_backlight_device;
pmu_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL);
if (!pmu_dev) {
printk("ALI M7101 PMU not found.\n");
return -ENODEV;
}
sb_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
if (!sb_dev) {
printk("ALI 1533 SB not found.\n");
pci_dev_put(pmu_dev);
return -ENODEV;
}
/* Set SB_MPS1 to enable brightness control. */
pci_read_config_byte(sb_dev, SB_MPS1, &temp);
pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20);
progear_backlight_device = backlight_device_register("progear-bl",
&pdev->dev, NULL,
&progearbl_ops);
if (IS_ERR(progear_backlight_device))
return PTR_ERR(progear_backlight_device);
platform_set_drvdata(pdev, progear_backlight_device);
progear_backlight_device->props.power = FB_BLANK_UNBLANK;
progear_backlight_device->props.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
progear_backlight_device->props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
progearbl_set_intensity(progear_backlight_device);
return 0;
}
static int progearbl_remove(struct platform_device *pdev)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
backlight_device_unregister(bd);
return 0;
}
static struct platform_driver progearbl_driver = {
.probe = progearbl_probe,
.remove = progearbl_remove,
.driver = {
.name = "progear-bl",
},
};
static struct platform_device *progearbl_device;
static int __init progearbl_init(void)
{
int ret = platform_driver_register(&progearbl_driver);
if (ret)
return ret;
progearbl_device = platform_device_register_simple("progear-bl", -1,
NULL, 0);
if (IS_ERR(progearbl_device)) {
platform_driver_unregister(&progearbl_driver);
return PTR_ERR(progearbl_device);
}
return 0;
}
static void __exit progearbl_exit(void)
{
pci_dev_put(pmu_dev);
pci_dev_put(sb_dev);
platform_device_unregister(progearbl_device);
platform_driver_unregister(&progearbl_driver);
}
module_init(progearbl_init);
module_exit(progearbl_exit);
MODULE_AUTHOR("Marcin Juszkiewicz <linux@hrw.one.pl>");
MODULE_DESCRIPTION("ProGear Backlight Driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,193 @@
/*
* linux/drivers/video/backlight/pwm_bl.c
*
* simple PWM based backlight control, board code has to setup
* 1) pin configuration so PWM waveforms can output
* 2) platform_data being correctly configured
*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/err.h>
#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
struct pwm_bl_data {
struct pwm_device *pwm;
unsigned int period;
int (*notify)(int brightness);
};
static int pwm_backlight_update_status(struct backlight_device *bl)
{
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
int brightness = bl->props.brightness;
int max = bl->props.max_brightness;
if (bl->props.power != FB_BLANK_UNBLANK)
brightness = 0;
if (bl->props.fb_blank != FB_BLANK_UNBLANK)
brightness = 0;
if (pb->notify)
brightness = pb->notify(brightness);
if (brightness == 0) {
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
} else {
pwm_config(pb->pwm, brightness * pb->period / max, pb->period);
pwm_enable(pb->pwm);
}
return 0;
}
static int pwm_backlight_get_brightness(struct backlight_device *bl)
{
return bl->props.brightness;
}
static struct backlight_ops pwm_backlight_ops = {
.update_status = pwm_backlight_update_status,
.get_brightness = pwm_backlight_get_brightness,
};
static int pwm_backlight_probe(struct platform_device *pdev)
{
struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
struct backlight_device *bl;
struct pwm_bl_data *pb;
int ret;
if (!data) {
dev_err(&pdev->dev, "failed to find platform data\n");
return -EINVAL;
}
if (data->init) {
ret = data->init(&pdev->dev);
if (ret < 0)
return ret;
}
pb = kzalloc(sizeof(*pb), GFP_KERNEL);
if (!pb) {
dev_err(&pdev->dev, "no memory for state\n");
ret = -ENOMEM;
goto err_alloc;
}
pb->period = data->pwm_period_ns;
pb->notify = data->notify;
pb->pwm = pwm_request(data->pwm_id, "backlight");
if (IS_ERR(pb->pwm)) {
dev_err(&pdev->dev, "unable to request PWM for backlight\n");
ret = PTR_ERR(pb->pwm);
goto err_pwm;
} else
dev_dbg(&pdev->dev, "got pwm for backlight\n");
bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,
pb, &pwm_backlight_ops);
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n");
ret = PTR_ERR(bl);
goto err_bl;
}
bl->props.max_brightness = data->max_brightness;
bl->props.brightness = data->dft_brightness;
backlight_update_status(bl);
platform_set_drvdata(pdev, bl);
return 0;
err_bl:
pwm_free(pb->pwm);
err_pwm:
kfree(pb);
err_alloc:
if (data->exit)
data->exit(&pdev->dev);
return ret;
}
static int pwm_backlight_remove(struct platform_device *pdev)
{
struct platform_pwm_backlight_data *data = pdev->dev.platform_data;
struct backlight_device *bl = platform_get_drvdata(pdev);
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
backlight_device_unregister(bl);
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
pwm_free(pb->pwm);
kfree(pb);
if (data->exit)
data->exit(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM
static int pwm_backlight_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct backlight_device *bl = platform_get_drvdata(pdev);
struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
if (pb->notify)
pb->notify(0);
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
return 0;
}
static int pwm_backlight_resume(struct platform_device *pdev)
{
struct backlight_device *bl = platform_get_drvdata(pdev);
backlight_update_status(bl);
return 0;
}
#else
#define pwm_backlight_suspend NULL
#define pwm_backlight_resume NULL
#endif
static struct platform_driver pwm_backlight_driver = {
.driver = {
.name = "pwm-backlight",
.owner = THIS_MODULE,
},
.probe = pwm_backlight_probe,
.remove = pwm_backlight_remove,
.suspend = pwm_backlight_suspend,
.resume = pwm_backlight_resume,
};
static int __init pwm_backlight_init(void)
{
return platform_driver_register(&pwm_backlight_driver);
}
module_init(pwm_backlight_init);
static void __exit pwm_backlight_exit(void)
{
platform_driver_unregister(&pwm_backlight_driver);
}
module_exit(pwm_backlight_exit);
MODULE_DESCRIPTION("PWM based Backlight Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pwm-backlight");

View File

@@ -0,0 +1,475 @@
/*
* tdo24m - SPI-based drivers for Toppoly TDO24M series LCD panels
*
* Copyright (C) 2008 Marvell International Ltd.
* Eric Miao <eric.miao@marvell.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
* publishhed by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/spi/tdo24m.h>
#include <linux/fb.h>
#include <linux/lcd.h>
#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
#define TDO24M_SPI_BUFF_SIZE (4)
#define MODE_QVGA 0
#define MODE_VGA 1
struct tdo24m {
struct spi_device *spi_dev;
struct lcd_device *lcd_dev;
struct spi_message msg;
struct spi_transfer xfer;
uint8_t *buf;
int (*adj_mode)(struct tdo24m *lcd, int mode);
int color_invert;
int power;
int mode;
};
/* use bit 30, 31 as the indicator of command parameter number */
#define CMD0(x) ((0 << 30) | (x))
#define CMD1(x, x1) ((1 << 30) | ((x) << 9) | 0x100 | (x1))
#define CMD2(x, x1, x2) ((2 << 30) | ((x) << 18) | 0x20000 |\
((x1) << 9) | 0x100 | (x2))
#define CMD_NULL (-1)
static uint32_t lcd_panel_reset[] = {
CMD0(0x1), /* reset */
CMD0(0x0), /* nop */
CMD0(0x0), /* nop */
CMD0(0x0), /* nop */
CMD_NULL,
};
static uint32_t lcd_panel_on[] = {
CMD0(0x29), /* Display ON */
CMD2(0xB8, 0xFF, 0xF9), /* Output Control */
CMD0(0x11), /* Sleep out */
CMD1(0xB0, 0x16), /* Wake */
CMD_NULL,
};
static uint32_t lcd_panel_off[] = {
CMD0(0x28), /* Display OFF */
CMD2(0xB8, 0x80, 0x02), /* Output Control */
CMD0(0x10), /* Sleep in */
CMD1(0xB0, 0x00), /* Deep stand by in */
CMD_NULL,
};
static uint32_t lcd_vga_pass_through_tdo24m[] = {
CMD1(0xB0, 0x16),
CMD1(0xBC, 0x80),
CMD1(0xE1, 0x00),
CMD1(0x36, 0x50),
CMD1(0x3B, 0x00),
CMD_NULL,
};
static uint32_t lcd_qvga_pass_through_tdo24m[] = {
CMD1(0xB0, 0x16),
CMD1(0xBC, 0x81),
CMD1(0xE1, 0x00),
CMD1(0x36, 0x50),
CMD1(0x3B, 0x22),
CMD_NULL,
};
static uint32_t lcd_vga_transfer_tdo24m[] = {
CMD1(0xcf, 0x02), /* Blanking period control (1) */
CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */
CMD1(0xd1, 0x01), /* CKV timing control on/off */
CMD2(0xd2, 0x14, 0x00), /* CKV 1,2 timing control */
CMD2(0xd3, 0x1a, 0x0f), /* OEV timing control */
CMD2(0xd4, 0x1f, 0xaf), /* ASW timing control (1) */
CMD1(0xd5, 0x14), /* ASW timing control (2) */
CMD0(0x21), /* Invert for normally black display */
CMD0(0x29), /* Display on */
CMD_NULL,
};
static uint32_t lcd_qvga_transfer[] = {
CMD1(0xd6, 0x02), /* Blanking period control (1) */
CMD2(0xd7, 0x08, 0x04), /* Blanking period control (2) */
CMD1(0xd8, 0x01), /* CKV timing control on/off */
CMD2(0xd9, 0x00, 0x08), /* CKV 1,2 timing control */
CMD2(0xde, 0x05, 0x0a), /* OEV timing control */
CMD2(0xdf, 0x0a, 0x19), /* ASW timing control (1) */
CMD1(0xe0, 0x0a), /* ASW timing control (2) */
CMD0(0x21), /* Invert for normally black display */
CMD0(0x29), /* Display on */
CMD_NULL,
};
static uint32_t lcd_vga_pass_through_tdo35s[] = {
CMD1(0xB0, 0x16),
CMD1(0xBC, 0x80),
CMD1(0xE1, 0x00),
CMD1(0x3B, 0x00),
CMD_NULL,
};
static uint32_t lcd_qvga_pass_through_tdo35s[] = {
CMD1(0xB0, 0x16),
CMD1(0xBC, 0x81),
CMD1(0xE1, 0x00),
CMD1(0x3B, 0x22),
CMD_NULL,
};
static uint32_t lcd_vga_transfer_tdo35s[] = {
CMD1(0xcf, 0x02), /* Blanking period control (1) */
CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */
CMD1(0xd1, 0x01), /* CKV timing control on/off */
CMD2(0xd2, 0x00, 0x1e), /* CKV 1,2 timing control */
CMD2(0xd3, 0x14, 0x28), /* OEV timing control */
CMD2(0xd4, 0x28, 0x64), /* ASW timing control (1) */
CMD1(0xd5, 0x28), /* ASW timing control (2) */
CMD0(0x21), /* Invert for normally black display */
CMD0(0x29), /* Display on */
CMD_NULL,
};
static uint32_t lcd_panel_config[] = {
CMD2(0xb8, 0xff, 0xf9), /* Output control */
CMD0(0x11), /* sleep out */
CMD1(0xba, 0x01), /* Display mode (1) */
CMD1(0xbb, 0x00), /* Display mode (2) */
CMD1(0x3a, 0x60), /* Display mode 18-bit RGB */
CMD1(0xbf, 0x10), /* Drive system change control */
CMD1(0xb1, 0x56), /* Booster operation setup */
CMD1(0xb2, 0x33), /* Booster mode setup */
CMD1(0xb3, 0x11), /* Booster frequency setup */
CMD1(0xb4, 0x02), /* Op amp/system clock */
CMD1(0xb5, 0x35), /* VCS voltage */
CMD1(0xb6, 0x40), /* VCOM voltage */
CMD1(0xb7, 0x03), /* External display signal */
CMD1(0xbd, 0x00), /* ASW slew rate */
CMD1(0xbe, 0x00), /* Dummy data for QuadData operation */
CMD1(0xc0, 0x11), /* Sleep out FR count (A) */
CMD1(0xc1, 0x11), /* Sleep out FR count (B) */
CMD1(0xc2, 0x11), /* Sleep out FR count (C) */
CMD2(0xc3, 0x20, 0x40), /* Sleep out FR count (D) */
CMD2(0xc4, 0x60, 0xc0), /* Sleep out FR count (E) */
CMD2(0xc5, 0x10, 0x20), /* Sleep out FR count (F) */
CMD1(0xc6, 0xc0), /* Sleep out FR count (G) */
CMD2(0xc7, 0x33, 0x43), /* Gamma 1 fine tuning (1) */
CMD1(0xc8, 0x44), /* Gamma 1 fine tuning (2) */
CMD1(0xc9, 0x33), /* Gamma 1 inclination adjustment */
CMD1(0xca, 0x00), /* Gamma 1 blue offset adjustment */
CMD2(0xec, 0x01, 0xf0), /* Horizontal clock cycles */
CMD_NULL,
};
static int tdo24m_writes(struct tdo24m *lcd, uint32_t *array)
{
struct spi_transfer *x = &lcd->xfer;
uint32_t data, *p = array;
int nparams, err = 0;
for (; *p != CMD_NULL; p++) {
if (!lcd->color_invert && *p == CMD0(0x21))
continue;
nparams = (*p >> 30) & 0x3;
data = *p << (7 - nparams);
switch (nparams) {
case 0:
lcd->buf[0] = (data >> 8) & 0xff;
lcd->buf[1] = data & 0xff;
break;
case 1:
lcd->buf[0] = (data >> 16) & 0xff;
lcd->buf[1] = (data >> 8) & 0xff;
lcd->buf[2] = data & 0xff;
break;
case 2:
lcd->buf[0] = (data >> 24) & 0xff;
lcd->buf[1] = (data >> 16) & 0xff;
lcd->buf[2] = (data >> 8) & 0xff;
lcd->buf[3] = data & 0xff;
break;
default:
continue;
}
x->len = nparams + 2;
err = spi_sync(lcd->spi_dev, &lcd->msg);
if (err)
break;
}
return err;
}
static int tdo24m_adj_mode(struct tdo24m *lcd, int mode)
{
switch (mode) {
case MODE_VGA:
tdo24m_writes(lcd, lcd_vga_pass_through_tdo24m);
tdo24m_writes(lcd, lcd_panel_config);
tdo24m_writes(lcd, lcd_vga_transfer_tdo24m);
break;
case MODE_QVGA:
tdo24m_writes(lcd, lcd_qvga_pass_through_tdo24m);
tdo24m_writes(lcd, lcd_panel_config);
tdo24m_writes(lcd, lcd_qvga_transfer);
break;
default:
return -EINVAL;
}
lcd->mode = mode;
return 0;
}
static int tdo35s_adj_mode(struct tdo24m *lcd, int mode)
{
switch (mode) {
case MODE_VGA:
tdo24m_writes(lcd, lcd_vga_pass_through_tdo35s);
tdo24m_writes(lcd, lcd_panel_config);
tdo24m_writes(lcd, lcd_vga_transfer_tdo35s);
break;
case MODE_QVGA:
tdo24m_writes(lcd, lcd_qvga_pass_through_tdo35s);
tdo24m_writes(lcd, lcd_panel_config);
tdo24m_writes(lcd, lcd_qvga_transfer);
break;
default:
return -EINVAL;
}
lcd->mode = mode;
return 0;
}
static int tdo24m_power_on(struct tdo24m *lcd)
{
int err;
err = tdo24m_writes(lcd, lcd_panel_on);
if (err)
goto out;
err = tdo24m_writes(lcd, lcd_panel_reset);
if (err)
goto out;
err = lcd->adj_mode(lcd, lcd->mode);
out:
return err;
}
static int tdo24m_power_off(struct tdo24m *lcd)
{
return tdo24m_writes(lcd, lcd_panel_off);
}
static int tdo24m_power(struct tdo24m *lcd, int power)
{
int ret = 0;
if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
ret = tdo24m_power_on(lcd);
else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
ret = tdo24m_power_off(lcd);
if (!ret)
lcd->power = power;
return ret;
}
static int tdo24m_set_power(struct lcd_device *ld, int power)
{
struct tdo24m *lcd = lcd_get_data(ld);
return tdo24m_power(lcd, power);
}
static int tdo24m_get_power(struct lcd_device *ld)
{
struct tdo24m *lcd = lcd_get_data(ld);
return lcd->power;
}
static int tdo24m_set_mode(struct lcd_device *ld, struct fb_videomode *m)
{
struct tdo24m *lcd = lcd_get_data(ld);
int mode = MODE_QVGA;
if (m->xres == 640 || m->xres == 480)
mode = MODE_VGA;
if (lcd->mode == mode)
return 0;
return lcd->adj_mode(lcd, mode);
}
static struct lcd_ops tdo24m_ops = {
.get_power = tdo24m_get_power,
.set_power = tdo24m_set_power,
.set_mode = tdo24m_set_mode,
};
static int __devinit tdo24m_probe(struct spi_device *spi)
{
struct tdo24m *lcd;
struct spi_message *m;
struct spi_transfer *x;
struct tdo24m_platform_data *pdata;
enum tdo24m_model model;
int err;
pdata = spi->dev.platform_data;
if (pdata)
model = pdata->model;
else
model = TDO24M;
spi->bits_per_word = 8;
spi->mode = SPI_MODE_3;
err = spi_setup(spi);
if (err)
return err;
lcd = kzalloc(sizeof(struct tdo24m), GFP_KERNEL);
if (!lcd)
return -ENOMEM;
lcd->spi_dev = spi;
lcd->power = FB_BLANK_POWERDOWN;
lcd->mode = MODE_VGA; /* default to VGA */
lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, GFP_KERNEL);
if (lcd->buf == NULL) {
kfree(lcd);
return -ENOMEM;
}
m = &lcd->msg;
x = &lcd->xfer;
spi_message_init(m);
x->tx_buf = &lcd->buf[0];
spi_message_add_tail(x, m);
switch (model) {
case TDO24M:
lcd->color_invert = 1;
lcd->adj_mode = tdo24m_adj_mode;
break;
case TDO35S:
lcd->adj_mode = tdo35s_adj_mode;
lcd->color_invert = 0;
break;
default:
dev_err(&spi->dev, "Unsupported model");
goto out_free;
}
lcd->lcd_dev = lcd_device_register("tdo24m", &spi->dev,
lcd, &tdo24m_ops);
if (IS_ERR(lcd->lcd_dev)) {
err = PTR_ERR(lcd->lcd_dev);
goto out_free;
}
dev_set_drvdata(&spi->dev, lcd);
err = tdo24m_power(lcd, FB_BLANK_UNBLANK);
if (err)
goto out_unregister;
return 0;
out_unregister:
lcd_device_unregister(lcd->lcd_dev);
out_free:
kfree(lcd->buf);
kfree(lcd);
return err;
}
static int __devexit tdo24m_remove(struct spi_device *spi)
{
struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
tdo24m_power(lcd, FB_BLANK_POWERDOWN);
lcd_device_unregister(lcd->lcd_dev);
kfree(lcd->buf);
kfree(lcd);
return 0;
}
#ifdef CONFIG_PM
static int tdo24m_suspend(struct spi_device *spi, pm_message_t state)
{
struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
return tdo24m_power(lcd, FB_BLANK_POWERDOWN);
}
static int tdo24m_resume(struct spi_device *spi)
{
struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
return tdo24m_power(lcd, FB_BLANK_UNBLANK);
}
#else
#define tdo24m_suspend NULL
#define tdo24m_resume NULL
#endif
/* Power down all displays on reboot, poweroff or halt */
static void tdo24m_shutdown(struct spi_device *spi)
{
struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
tdo24m_power(lcd, FB_BLANK_POWERDOWN);
}
static struct spi_driver tdo24m_driver = {
.driver = {
.name = "tdo24m",
.owner = THIS_MODULE,
},
.probe = tdo24m_probe,
.remove = __devexit_p(tdo24m_remove),
.shutdown = tdo24m_shutdown,
.suspend = tdo24m_suspend,
.resume = tdo24m_resume,
};
static int __init tdo24m_init(void)
{
return spi_register_driver(&tdo24m_driver);
}
module_init(tdo24m_init);
static void __exit tdo24m_exit(void)
{
spi_unregister_driver(&tdo24m_driver);
}
module_exit(tdo24m_exit);
MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>");
MODULE_DESCRIPTION("Driver for Toppoly TDO24M LCD Panel");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:tdo24m");

View File

@@ -0,0 +1,198 @@
/*
* LCD / Backlight control code for Sharp SL-6000x (tosa)
*
* Copyright (c) 2005 Dirk Opfer
* Copyright (c) 2007,2008 Dmitry Baryshkov
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <asm/mach/sharpsl_param.h>
#include <mach/tosa.h>
#define COMADJ_DEFAULT 97
#define DAC_CH1 0
#define DAC_CH2 1
struct tosa_bl_data {
struct i2c_client *i2c;
struct backlight_device *bl;
int comadj;
};
static void tosa_bl_set_backlight(struct tosa_bl_data *data, int brightness)
{
struct spi_device *spi = data->i2c->dev.platform_data;
i2c_smbus_write_byte_data(data->i2c, DAC_CH1, data->comadj);
/* SetBacklightDuty */
i2c_smbus_write_byte_data(data->i2c, DAC_CH2, (u8)(brightness & 0xff));
/* SetBacklightVR */
gpio_set_value(TOSA_GPIO_BL_C20MA, brightness & 0x100);
tosa_bl_enable(spi, brightness);
}
static int tosa_bl_update_status(struct backlight_device *dev)
{
struct backlight_properties *props = &dev->props;
struct tosa_bl_data *data = dev_get_drvdata(&dev->dev);
int power = max(props->power, props->fb_blank);
int brightness = props->brightness;
if (power)
brightness = 0;
tosa_bl_set_backlight(data, brightness);
return 0;
}
static int tosa_bl_get_brightness(struct backlight_device *dev)
{
struct backlight_properties *props = &dev->props;
return props->brightness;
}
static struct backlight_ops bl_ops = {
.get_brightness = tosa_bl_get_brightness,
.update_status = tosa_bl_update_status,
};
static int __devinit tosa_bl_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tosa_bl_data *data = kzalloc(sizeof(struct tosa_bl_data), GFP_KERNEL);
int ret = 0;
if (!data)
return -ENOMEM;
data->comadj = sharpsl_param.comadj == -1 ? COMADJ_DEFAULT : sharpsl_param.comadj;
ret = gpio_request(TOSA_GPIO_BL_C20MA, "backlight");
if (ret) {
dev_dbg(&data->bl->dev, "Unable to request gpio!\n");
goto err_gpio_bl;
}
ret = gpio_direction_output(TOSA_GPIO_BL_C20MA, 0);
if (ret)
goto err_gpio_dir;
i2c_set_clientdata(client, data);
data->i2c = client;
data->bl = backlight_device_register("tosa-bl", &client->dev,
data, &bl_ops);
if (IS_ERR(data->bl)) {
ret = PTR_ERR(data->bl);
goto err_reg;
}
data->bl->props.brightness = 69;
data->bl->props.max_brightness = 512 - 1;
data->bl->props.power = FB_BLANK_UNBLANK;
backlight_update_status(data->bl);
return 0;
err_reg:
data->bl = NULL;
i2c_set_clientdata(client, NULL);
err_gpio_dir:
gpio_free(TOSA_GPIO_BL_C20MA);
err_gpio_bl:
kfree(data);
return ret;
}
static int __devexit tosa_bl_remove(struct i2c_client *client)
{
struct tosa_bl_data *data = i2c_get_clientdata(client);
backlight_device_unregister(data->bl);
data->bl = NULL;
i2c_set_clientdata(client, NULL);
gpio_free(TOSA_GPIO_BL_C20MA);
kfree(data);
return 0;
}
#ifdef CONFIG_PM
static int tosa_bl_suspend(struct i2c_client *client, pm_message_t pm)
{
struct tosa_bl_data *data = i2c_get_clientdata(client);
tosa_bl_set_backlight(data, 0);
return 0;
}
static int tosa_bl_resume(struct i2c_client *client)
{
struct tosa_bl_data *data = i2c_get_clientdata(client);
backlight_update_status(data->bl);
return 0;
}
#else
#define tosa_bl_suspend NULL
#define tosa_bl_resume NULL
#endif
static const struct i2c_device_id tosa_bl_id[] = {
{ "tosa-bl", 0 },
{ },
};
static struct i2c_driver tosa_bl_driver = {
.driver = {
.name = "tosa-bl",
.owner = THIS_MODULE,
},
.probe = tosa_bl_probe,
.remove = __devexit_p(tosa_bl_remove),
.suspend = tosa_bl_suspend,
.resume = tosa_bl_resume,
.id_table = tosa_bl_id,
};
static int __init tosa_bl_init(void)
{
return i2c_add_driver(&tosa_bl_driver);
}
static void __exit tosa_bl_exit(void)
{
i2c_del_driver(&tosa_bl_driver);
}
module_init(tosa_bl_init);
module_exit(tosa_bl_exit);
MODULE_AUTHOR("Dmitry Baryshkov");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("LCD/Backlight control for Sharp SL-6000 PDA");

View File

@@ -0,0 +1,303 @@
/*
* LCD / Backlight control code for Sharp SL-6000x (tosa)
*
* Copyright (c) 2005 Dirk Opfer
* Copyright (c) 2007,2008 Dmitry Baryshkov
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/lcd.h>
#include <linux/fb.h>
#include <asm/mach/sharpsl_param.h>
#include <mach/tosa.h>
#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
#define TG_REG0_VQV 0x0001
#define TG_REG0_COLOR 0x0002
#define TG_REG0_UD 0x0004
#define TG_REG0_LR 0x0008
#define DAC_BASE 0x4e
struct tosa_lcd_data {
struct spi_device *spi;
struct lcd_device *lcd;
struct i2c_client *i2c;
int lcd_power;
bool is_vga;
};
static int tosa_tg_send(struct spi_device *spi, int adrs, uint8_t data)
{
u8 buf[1];
struct spi_message msg;
struct spi_transfer xfer = {
.len = 1,
.cs_change = 1,
.tx_buf = buf,
};
buf[0] = ((adrs & 0x07) << 5) | (data & 0x1f);
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
return spi_sync(spi, &msg);
}
int tosa_bl_enable(struct spi_device *spi, int enable)
{
/* bl_enable GP04=1 otherwise GP04=0*/
return tosa_tg_send(spi, TG_GPODR2, enable? 0x01 : 0x00);
}
EXPORT_SYMBOL(tosa_bl_enable);
static void tosa_lcd_tg_init(struct tosa_lcd_data *data)
{
/* TG on */
gpio_set_value(TOSA_GPIO_TG_ON, 0);
mdelay(60);
/* delayed 0clk TCTL signal for VGA */
tosa_tg_send(data->spi, TG_TPOSCTL, 0x00);
/* GPOS0=powercontrol, GPOS1=GPIO, GPOS2=TCTL */
tosa_tg_send(data->spi, TG_GPOSR, 0x02);
}
static void tosa_lcd_tg_on(struct tosa_lcd_data *data)
{
struct spi_device *spi = data->spi;
int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR;
if (data->is_vga)
value |= TG_REG0_VQV;
tosa_tg_send(spi, TG_PNLCTL, value);
/* TG LCD pannel power up */
tosa_tg_send(spi, TG_PINICTL,0x4);
mdelay(50);
/* TG LCD GVSS */
tosa_tg_send(spi, TG_PINICTL,0x0);
if (!data->i2c) {
/* after the pannel is powered up the first time, we can access the i2c bus */
/* so probe for the DAC */
struct i2c_adapter *adap = i2c_get_adapter(0);
struct i2c_board_info info = {
.type = "tosa-bl",
.addr = DAC_BASE,
.platform_data = data->spi,
};
data->i2c = i2c_new_device(adap, &info);
}
}
static void tosa_lcd_tg_off(struct tosa_lcd_data *data)
{
struct spi_device *spi = data->spi;
/* TG LCD VHSA off */
tosa_tg_send(spi, TG_PINICTL,0x4);
mdelay(50);
/* TG LCD signal off */
tosa_tg_send(spi, TG_PINICTL,0x6);
mdelay(50);
/* TG Off */
gpio_set_value(TOSA_GPIO_TG_ON, 1);
mdelay(100);
}
int tosa_lcd_set_power(struct lcd_device *lcd, int power)
{
struct tosa_lcd_data *data = lcd_get_data(lcd);
if (POWER_IS_ON(power) && !POWER_IS_ON(data->lcd_power))
tosa_lcd_tg_on(data);
if (!POWER_IS_ON(power) && POWER_IS_ON(data->lcd_power))
tosa_lcd_tg_off(data);
data->lcd_power = power;
return 0;
}
static int tosa_lcd_get_power(struct lcd_device *lcd)
{
struct tosa_lcd_data *data = lcd_get_data(lcd);
return data->lcd_power;
}
static int tosa_lcd_set_mode(struct lcd_device *lcd, struct fb_videomode *mode)
{
struct tosa_lcd_data *data = lcd_get_data(lcd);
if (mode->xres == 320 || mode->yres == 320)
data->is_vga = false;
else
data->is_vga = true;
if (POWER_IS_ON(data->lcd_power))
tosa_lcd_tg_on(data);
return 0;
}
static struct lcd_ops tosa_lcd_ops = {
.set_power = tosa_lcd_set_power,
.get_power = tosa_lcd_get_power,
.set_mode = tosa_lcd_set_mode,
};
static int __devinit tosa_lcd_probe(struct spi_device *spi)
{
int ret;
struct tosa_lcd_data *data;
data = kzalloc(sizeof(struct tosa_lcd_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->is_vga = true; /* defaut to VGA mode */
/*
* bits_per_word cannot be configured in platform data
*/
spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret < 0)
goto err_spi;
data->spi = spi;
dev_set_drvdata(&spi->dev, data);
ret = gpio_request(TOSA_GPIO_TG_ON, "tg #pwr");
if (ret < 0)
goto err_gpio_tg;
mdelay(60);
ret = gpio_direction_output(TOSA_GPIO_TG_ON, 0);
if (ret < 0)
goto err_gpio_dir;
mdelay(60);
tosa_lcd_tg_init(data);
tosa_lcd_tg_on(data);
data->lcd = lcd_device_register("tosa-lcd", &spi->dev, data,
&tosa_lcd_ops);
if (IS_ERR(data->lcd)) {
ret = PTR_ERR(data->lcd);
data->lcd = NULL;
goto err_register;
}
return 0;
err_register:
tosa_lcd_tg_off(data);
err_gpio_dir:
gpio_free(TOSA_GPIO_TG_ON);
err_gpio_tg:
dev_set_drvdata(&spi->dev, NULL);
err_spi:
kfree(data);
return ret;
}
static int __devexit tosa_lcd_remove(struct spi_device *spi)
{
struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev);
lcd_device_unregister(data->lcd);
if (data->i2c)
i2c_unregister_device(data->i2c);
tosa_lcd_tg_off(data);
gpio_free(TOSA_GPIO_TG_ON);
dev_set_drvdata(&spi->dev, NULL);
kfree(data);
return 0;
}
#ifdef CONFIG_PM
static int tosa_lcd_suspend(struct spi_device *spi, pm_message_t state)
{
struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev);
tosa_lcd_tg_off(data);
return 0;
}
static int tosa_lcd_resume(struct spi_device *spi)
{
struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev);
tosa_lcd_tg_init(data);
if (POWER_IS_ON(data->lcd_power))
tosa_lcd_tg_on(data);
else
tosa_lcd_tg_off(data);
return 0;
}
#else
#define tosa_lcd_suspend NULL
#define tosa_lcd_reume NULL
#endif
static struct spi_driver tosa_lcd_driver = {
.driver = {
.name = "tosa-lcd",
.owner = THIS_MODULE,
},
.probe = tosa_lcd_probe,
.remove = __devexit_p(tosa_lcd_remove),
.suspend = tosa_lcd_suspend,
.resume = tosa_lcd_resume,
};
static int __init tosa_lcd_init(void)
{
return spi_register_driver(&tosa_lcd_driver);
}
static void __exit tosa_lcd_exit(void)
{
spi_unregister_driver(&tosa_lcd_driver);
}
module_init(tosa_lcd_init);
module_exit(tosa_lcd_exit);
MODULE_AUTHOR("Dmitry Baryshkov");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("LCD/Backlight control for Sharp SL-6000 PDA");
MODULE_ALIAS("spi:tosa-lcd");

View File

@@ -0,0 +1,283 @@
/* drivers/video/backlight/vgg2432a4.c
*
* VGG2432A4 (ILI9320) LCD controller driver.
*
* Copyright 2007 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* 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.
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/lcd.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <video/ili9320.h>
#include "ili9320.h"
/* Device initialisation sequences */
static struct ili9320_reg vgg_init1[] = {
{
.address = ILI9320_POWER1,
.value = ILI9320_POWER1_AP(0) | ILI9320_POWER1_BT(0),
}, {
.address = ILI9320_POWER2,
.value = (ILI9320_POWER2_VC(7) |
ILI9320_POWER2_DC0(0) | ILI9320_POWER2_DC1(0)),
}, {
.address = ILI9320_POWER3,
.value = ILI9320_POWER3_VRH(0),
}, {
.address = ILI9320_POWER4,
.value = ILI9320_POWER4_VREOUT(0),
},
};
static struct ili9320_reg vgg_init2[] = {
{
.address = ILI9320_POWER1,
.value = (ILI9320_POWER1_AP(3) | ILI9320_POWER1_APE |
ILI9320_POWER1_BT(7) | ILI9320_POWER1_SAP),
}, {
.address = ILI9320_POWER2,
.value = ILI9320_POWER2_VC(7) | ILI9320_POWER2_DC0(3),
}
};
static struct ili9320_reg vgg_gamma[] = {
{
.address = ILI9320_GAMMA1,
.value = 0x0000,
}, {
.address = ILI9320_GAMMA2,
.value = 0x0505,
}, {
.address = ILI9320_GAMMA3,
.value = 0x0004,
}, {
.address = ILI9320_GAMMA4,
.value = 0x0006,
}, {
.address = ILI9320_GAMMA5,
.value = 0x0707,
}, {
.address = ILI9320_GAMMA6,
.value = 0x0105,
}, {
.address = ILI9320_GAMMA7,
.value = 0x0002,
}, {
.address = ILI9320_GAMMA8,
.value = 0x0707,
}, {
.address = ILI9320_GAMMA9,
.value = 0x0704,
}, {
.address = ILI9320_GAMMA10,
.value = 0x807,
}
};
static struct ili9320_reg vgg_init0[] = {
[0] = {
/* set direction and scan mode gate */
.address = ILI9320_DRIVER,
.value = ILI9320_DRIVER_SS,
}, {
.address = ILI9320_DRIVEWAVE,
.value = (ILI9320_DRIVEWAVE_MUSTSET |
ILI9320_DRIVEWAVE_EOR | ILI9320_DRIVEWAVE_BC),
}, {
.address = ILI9320_ENTRYMODE,
.value = ILI9320_ENTRYMODE_ID(3) | ILI9320_ENTRYMODE_BGR,
}, {
.address = ILI9320_RESIZING,
.value = 0x0,
},
};
static int vgg2432a4_lcd_init(struct ili9320 *lcd,
struct ili9320_platdata *cfg)
{
unsigned int addr;
int ret;
/* Set VCore before anything else (VGG243237-6UFLWA) */
ret = ili9320_write(lcd, 0x00e5, 0x8000);
if (ret)
goto err_initial;
/* Start the oscillator up before we can do anything else. */
ret = ili9320_write(lcd, ILI9320_OSCILATION, ILI9320_OSCILATION_OSC);
if (ret)
goto err_initial;
/* must wait at-lesat 10ms after starting */
mdelay(15);
ret = ili9320_write_regs(lcd, vgg_init0, ARRAY_SIZE(vgg_init0));
if (ret != 0)
goto err_initial;
ili9320_write(lcd, ILI9320_DISPLAY2, cfg->display2);
ili9320_write(lcd, ILI9320_DISPLAY3, cfg->display3);
ili9320_write(lcd, ILI9320_DISPLAY4, cfg->display4);
ili9320_write(lcd, ILI9320_RGB_IF1, cfg->rgb_if1);
ili9320_write(lcd, ILI9320_FRAMEMAKER, 0x0);
ili9320_write(lcd, ILI9320_RGB_IF2, cfg->rgb_if2);
ret = ili9320_write_regs(lcd, vgg_init1, ARRAY_SIZE(vgg_init1));
if (ret != 0)
goto err_vgg;
mdelay(300);
ret = ili9320_write_regs(lcd, vgg_init2, ARRAY_SIZE(vgg_init2));
if (ret != 0)
goto err_vgg2;
mdelay(100);
ili9320_write(lcd, ILI9320_POWER3, 0x13c);
mdelay(100);
ili9320_write(lcd, ILI9320_POWER4, 0x1c00);
ili9320_write(lcd, ILI9320_POWER7, 0x000e);
mdelay(100);
ili9320_write(lcd, ILI9320_GRAM_HORIZ_ADDR, 0x00);
ili9320_write(lcd, ILI9320_GRAM_VERT_ADD, 0x00);
ret = ili9320_write_regs(lcd, vgg_gamma, ARRAY_SIZE(vgg_gamma));
if (ret != 0)
goto err_vgg3;
ili9320_write(lcd, ILI9320_HORIZ_START, 0x0);
ili9320_write(lcd, ILI9320_HORIZ_END, cfg->hsize - 1);
ili9320_write(lcd, ILI9320_VERT_START, 0x0);
ili9320_write(lcd, ILI9320_VERT_END, cfg->vsize - 1);
ili9320_write(lcd, ILI9320_DRIVER2,
ILI9320_DRIVER2_NL(((cfg->vsize - 240) / 8) + 0x1D));
ili9320_write(lcd, ILI9320_BASE_IMAGE, 0x1);
ili9320_write(lcd, ILI9320_VERT_SCROLL, 0x00);
for (addr = ILI9320_PARTIAL1_POSITION; addr <= ILI9320_PARTIAL2_END;
addr++) {
ili9320_write(lcd, addr, 0x0);
}
ili9320_write(lcd, ILI9320_INTERFACE1, 0x10);
ili9320_write(lcd, ILI9320_INTERFACE2, cfg->interface2);
ili9320_write(lcd, ILI9320_INTERFACE3, cfg->interface3);
ili9320_write(lcd, ILI9320_INTERFACE4, cfg->interface4);
ili9320_write(lcd, ILI9320_INTERFACE5, cfg->interface5);
ili9320_write(lcd, ILI9320_INTERFACE6, cfg->interface6);
lcd->display1 = (ILI9320_DISPLAY1_D(3) | ILI9320_DISPLAY1_DTE |
ILI9320_DISPLAY1_GON | ILI9320_DISPLAY1_BASEE |
0x40);
ili9320_write(lcd, ILI9320_DISPLAY1, lcd->display1);
return 0;
err_vgg3:
err_vgg2:
err_vgg:
err_initial:
return ret;
}
#ifdef CONFIG_PM
static int vgg2432a4_suspend(struct spi_device *spi, pm_message_t state)
{
return ili9320_suspend(dev_get_drvdata(&spi->dev), state);
}
static int vgg2432a4_resume(struct spi_device *spi)
{
return ili9320_resume(dev_get_drvdata(&spi->dev));
}
#else
#define vgg2432a4_suspend NULL
#define vgg2432a4_resume NULL
#endif
static struct ili9320_client vgg2432a4_client = {
.name = "VGG2432A4",
.init = vgg2432a4_lcd_init,
};
/* Device probe */
static int __devinit vgg2432a4_probe(struct spi_device *spi)
{
int ret;
ret = ili9320_probe_spi(spi, &vgg2432a4_client);
if (ret != 0) {
dev_err(&spi->dev, "failed to initialise ili9320\n");
return ret;
}
return 0;
}
static int __devexit vgg2432a4_remove(struct spi_device *spi)
{
return ili9320_remove(dev_get_drvdata(&spi->dev));
}
static void vgg2432a4_shutdown(struct spi_device *spi)
{
ili9320_shutdown(dev_get_drvdata(&spi->dev));
}
static struct spi_driver vgg2432a4_driver = {
.driver = {
.name = "VGG2432A4",
.owner = THIS_MODULE,
},
.probe = vgg2432a4_probe,
.remove = __devexit_p(vgg2432a4_remove),
.shutdown = vgg2432a4_shutdown,
.suspend = vgg2432a4_suspend,
.resume = vgg2432a4_resume,
};
/* Device driver initialisation */
static int __init vgg2432a4_init(void)
{
return spi_register_driver(&vgg2432a4_driver);
}
static void __exit vgg2432a4_exit(void)
{
spi_unregister_driver(&vgg2432a4_driver);
}
module_init(vgg2432a4_init);
module_exit(vgg2432a4_exit);
MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
MODULE_DESCRIPTION("VGG2432A4 LCD Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:VGG2432A4");

View File

@@ -0,0 +1,250 @@
/*
* Backlight driver for Wolfson Microelectronics WM831x PMICs
*
* Copyright 2009 Wolfson Microelectonics plc
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/regulator.h>
struct wm831x_backlight_data {
struct wm831x *wm831x;
int isink_reg;
int current_brightness;
};
static int wm831x_backlight_set(struct backlight_device *bl, int brightness)
{
struct wm831x_backlight_data *data = bl_get_data(bl);
struct wm831x *wm831x = data->wm831x;
int power_up = !data->current_brightness && brightness;
int power_down = data->current_brightness && !brightness;
int ret;
if (power_up) {
/* Enable the ISINK */
ret = wm831x_set_bits(wm831x, data->isink_reg,
WM831X_CS1_ENA, WM831X_CS1_ENA);
if (ret < 0)
goto err;
/* Enable the DC-DC */
ret = wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE,
WM831X_DC4_ENA, WM831X_DC4_ENA);
if (ret < 0)
goto err;
}
if (power_down) {
/* DCDC first */
ret = wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE,
WM831X_DC4_ENA, 0);
if (ret < 0)
goto err;
/* ISINK */
ret = wm831x_set_bits(wm831x, data->isink_reg,
WM831X_CS1_DRIVE | WM831X_CS1_ENA, 0);
if (ret < 0)
goto err;
}
/* Set the new brightness */
ret = wm831x_set_bits(wm831x, data->isink_reg,
WM831X_CS1_ISEL_MASK, brightness);
if (ret < 0)
goto err;
if (power_up) {
/* Drive current through the ISINK */
ret = wm831x_set_bits(wm831x, data->isink_reg,
WM831X_CS1_DRIVE, WM831X_CS1_DRIVE);
if (ret < 0)
return ret;
}
data->current_brightness = brightness;
return 0;
err:
/* If we were in the middle of a power transition always shut down
* for safety.
*/
if (power_up || power_down) {
wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, WM831X_DC4_ENA, 0);
wm831x_set_bits(wm831x, data->isink_reg, WM831X_CS1_ENA, 0);
}
return ret;
}
static int wm831x_backlight_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;
if (bl->props.state & BL_CORE_SUSPENDED)
brightness = 0;
return wm831x_backlight_set(bl, brightness);
}
static int wm831x_backlight_get_brightness(struct backlight_device *bl)
{
struct wm831x_backlight_data *data = bl_get_data(bl);
return data->current_brightness;
}
static struct backlight_ops wm831x_backlight_ops = {
.options = BL_CORE_SUSPENDRESUME,
.update_status = wm831x_backlight_update_status,
.get_brightness = wm831x_backlight_get_brightness,
};
static int wm831x_backlight_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *wm831x_pdata;
struct wm831x_backlight_pdata *pdata;
struct wm831x_backlight_data *data;
struct backlight_device *bl;
int ret, i, max_isel, isink_reg, dcdc_cfg;
/* We need platform data */
if (pdev->dev.parent->platform_data) {
wm831x_pdata = pdev->dev.parent->platform_data;
pdata = wm831x_pdata->backlight;
} else {
pdata = NULL;
}
if (!pdata) {
dev_err(&pdev->dev, "No platform data supplied\n");
return -EINVAL;
}
/* Figure out the maximum current we can use */
for (i = 0; i < WM831X_ISINK_MAX_ISEL; i++) {
if (wm831x_isinkv_values[i] > pdata->max_uA)
break;
}
if (i == 0) {
dev_err(&pdev->dev, "Invalid max_uA: %duA\n", pdata->max_uA);
return -EINVAL;
}
max_isel = i - 1;
if (pdata->max_uA != wm831x_isinkv_values[max_isel])
dev_warn(&pdev->dev,
"Maximum current is %duA not %duA as requested\n",
wm831x_isinkv_values[max_isel], pdata->max_uA);
switch (pdata->isink) {
case 1:
isink_reg = WM831X_CURRENT_SINK_1;
dcdc_cfg = 0;
break;
case 2:
isink_reg = WM831X_CURRENT_SINK_2;
dcdc_cfg = WM831X_DC4_FBSRC;
break;
default:
dev_err(&pdev->dev, "Invalid ISINK %d\n", pdata->isink);
return -EINVAL;
}
/* Configure the ISINK to use for feedback */
ret = wm831x_reg_unlock(wm831x);
if (ret < 0)
return ret;
ret = wm831x_set_bits(wm831x, WM831X_DC4_CONTROL, WM831X_DC4_FBSRC,
dcdc_cfg);
wm831x_reg_lock(wm831x);
if (ret < 0)
return ret;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
data->wm831x = wm831x;
data->current_brightness = 0;
data->isink_reg = isink_reg;
bl = backlight_device_register("wm831x", &pdev->dev,
data, &wm831x_backlight_ops);
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n");
kfree(data);
return PTR_ERR(bl);
}
bl->props.max_brightness = max_isel;
bl->props.brightness = max_isel;
platform_set_drvdata(pdev, bl);
/* Disable the DCDC if it was started so we can bootstrap */
wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, WM831X_DC4_ENA, 0);
backlight_update_status(bl);
return 0;
}
static int wm831x_backlight_remove(struct platform_device *pdev)
{
struct backlight_device *bl = platform_get_drvdata(pdev);
struct wm831x_backlight_data *data = bl_get_data(bl);
backlight_device_unregister(bl);
kfree(data);
return 0;
}
static struct platform_driver wm831x_backlight_driver = {
.driver = {
.name = "wm831x-backlight",
.owner = THIS_MODULE,
},
.probe = wm831x_backlight_probe,
.remove = wm831x_backlight_remove,
};
static int __init wm831x_backlight_init(void)
{
return platform_driver_register(&wm831x_backlight_driver);
}
module_init(wm831x_backlight_init);
static void __exit wm831x_backlight_exit(void)
{
platform_driver_unregister(&wm831x_backlight_driver);
}
module_exit(wm831x_backlight_exit);
MODULE_DESCRIPTION("Backlight Driver for WM831x PMICs");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wm831x-backlight");