Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 83570
b: refs/heads/master
c: a9a84c3
h: refs/heads/master
v: v3
  • Loading branch information
David Brownell authored and Linus Torvalds committed Feb 6, 2008
1 parent 5ce4c9a commit 194ac17
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b1230ee50a9903a987feaad767fb71e2fd173894
refs/heads/master: a9a84c37d1ee50db8f3752b117caf2b48dcd4f8a
1 change: 1 addition & 0 deletions trunk/arch/arm/mach-at91/board-sam9261ek.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ static void at91_lcdc_tft_power_control(int on)
}

static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
.lcdcon_is_backlight = true,
.default_bpp = 16,
.default_dmacon = ATMEL_LCDC_DMAEN,
.default_lcdcon2 = AT91SAM9261_DEFAULT_TFT_LCDCON2,
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/arm/mach-at91/board-sam9263ek.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ static void at91_lcdc_power_control(int on)

/* Driver datas */
static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
.lcdcon_is_backlight = true,
.default_bpp = 16,
.default_dmacon = ATMEL_LCDC_DMAEN,
.default_lcdcon2 = AT91SAM9263_DEFAULT_LCDCON2,
Expand Down
115 changes: 111 additions & 4 deletions trunk/drivers/video/atmel_lcdfb.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/backlight.h>

#include <asm/arch/board.h>
#include <asm/arch/cpu.h>
Expand Down Expand Up @@ -69,6 +70,107 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
}
#endif

static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
| ATMEL_LCDC_POL_POSITIVE
| ATMEL_LCDC_ENA_PWMENABLE;

#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC

/* some bl->props field just changed */
static int atmel_bl_update_status(struct backlight_device *bl)
{
struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
int power = sinfo->bl_power;
int brightness = bl->props.brightness;

/* REVISIT there may be a meaningful difference between
* fb_blank and power ... there seem to be some cases
* this doesn't handle correctly.
*/
if (bl->props.fb_blank != sinfo->bl_power)
power = bl->props.fb_blank;
else if (bl->props.power != sinfo->bl_power)
power = bl->props.power;

if (brightness < 0 && power == FB_BLANK_UNBLANK)
brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
else if (power != FB_BLANK_UNBLANK)
brightness = 0;

lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
brightness ? contrast_ctr : 0);

bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;

return 0;
}

static int atmel_bl_get_brightness(struct backlight_device *bl)
{
struct atmel_lcdfb_info *sinfo = bl_get_data(bl);

return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
}

static struct backlight_ops atmel_lcdc_bl_ops = {
.update_status = atmel_bl_update_status,
.get_brightness = atmel_bl_get_brightness,
};

static void init_backlight(struct atmel_lcdfb_info *sinfo)
{
struct backlight_device *bl;

sinfo->bl_power = FB_BLANK_UNBLANK;

if (sinfo->backlight)
return;

bl = backlight_device_register("backlight", &sinfo->pdev->dev,
sinfo, &atmel_lcdc_bl_ops);
if (IS_ERR(sinfo->backlight)) {
dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
PTR_ERR(bl));
return;
}
sinfo->backlight = bl;

bl->props.power = FB_BLANK_UNBLANK;
bl->props.fb_blank = FB_BLANK_UNBLANK;
bl->props.max_brightness = 0xff;
bl->props.brightness = atmel_bl_get_brightness(bl);
}

static void exit_backlight(struct atmel_lcdfb_info *sinfo)
{
if (sinfo->backlight)
backlight_device_unregister(sinfo->backlight);
}

#else

static void init_backlight(struct atmel_lcdfb_info *sinfo)
{
dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
}

static void exit_backlight(struct atmel_lcdfb_info *sinfo)
{
}

#endif

static void init_contrast(struct atmel_lcdfb_info *sinfo)
{
/* have some default contrast/backlight settings */
lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);

if (sinfo->lcdcon_is_backlight)
init_backlight(sinfo);
}


static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
.type = FB_TYPE_PACKED_PIXELS,
Expand Down Expand Up @@ -390,10 +492,6 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
/* Disable all interrupts */
lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);

/* Set contrast */
value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
/* ...wait for DMA engine to become idle... */
while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
msleep(10);
Expand Down Expand Up @@ -597,6 +695,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
sinfo->default_monspecs = pdata_sinfo->default_monspecs;
sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
sinfo->guard_time = pdata_sinfo->guard_time;
sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
} else {
dev_err(dev, "cannot get default configuration\n");
goto free_info;
Expand Down Expand Up @@ -690,6 +789,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
goto release_mem;
}

/* Initialize PWM for contrast or backlight ("off") */
init_contrast(sinfo);

/* interrupt */
ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
if (ret) {
Expand Down Expand Up @@ -741,6 +843,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
unregister_irqs:
free_irq(sinfo->irq_base, info);
unmap_mmio:
exit_backlight(sinfo);
iounmap(sinfo->mmio);
release_mem:
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
Expand Down Expand Up @@ -775,6 +878,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
if (!sinfo)
return 0;

exit_backlight(sinfo);
if (sinfo->atmel_lcdfb_power_control)
sinfo->atmel_lcdfb_power_control(0);
unregister_framebuffer(info);
Expand All @@ -801,6 +905,9 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)

static struct platform_driver atmel_lcdfb_driver = {
.remove = __exit_p(atmel_lcdfb_remove),

// FIXME need suspend, resume

.driver = {
.name = "atmel_lcdfb",
.owner = THIS_MODULE,
Expand Down
13 changes: 13 additions & 0 deletions trunk/drivers/video/backlight/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ config BACKLIGHT_CLASS_DEVICE
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_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_CORGI
tristate "Generic (aka Sharp Corgi) Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE
Expand Down
11 changes: 9 additions & 2 deletions trunk/include/video/atmel_lcdc.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#ifndef __ATMEL_LCDC_H__
#define __ATMEL_LCDC_H__

/* LCD Controller info data structure */
/* LCD Controller info data structure, stored in device platform_data */
struct atmel_lcdfb_info {
spinlock_t lock;
struct fb_info *info;
Expand All @@ -33,7 +33,14 @@ struct atmel_lcdfb_info {
struct platform_device *pdev;
struct clk *bus_clk;
struct clk *lcdc_clk;
unsigned int default_bpp;

#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
struct backlight_device *backlight;
u8 bl_power;
#endif
bool lcdcon_is_backlight;

u8 default_bpp;
unsigned int default_lcdcon2;
unsigned int default_dmacon;
void (*atmel_lcdfb_power_control)(int on);
Expand Down

0 comments on commit 194ac17

Please sign in to comment.