This is a backlight driver for FIC's Neo1973 Phone (codename GTA01) Index: linux-2.6.21.3-moko/drivers/video/backlight/Kconfig =================================================================== --- linux-2.6.21.3-moko.orig/drivers/video/backlight/Kconfig +++ linux-2.6.21.3-moko/drivers/video/backlight/Kconfig @@ -48,6 +48,14 @@ If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to enable the LCD/backlight driver. +config BACKLIGHT_GTA01 + tristate "FIC Neo1973 GTA01 Backlight Driver" + depends on BACKLIGHT_CLASS_DEVICE && MACH_NEO1973_GTA01 + default y + help + If you have a FIC GTA01 say y to enable the backlight driver. + + config BACKLIGHT_HP680 tristate "HP Jornada 680 Backlight Driver" depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX Index: linux-2.6.21.3-moko/drivers/video/backlight/Makefile =================================================================== --- linux-2.6.21.3-moko.orig/drivers/video/backlight/Makefile +++ linux-2.6.21.3-moko/drivers/video/backlight/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o +obj-$(CONFIG_BACKLIGHT_GTA01) += gta01_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o Index: linux-2.6.21.3-moko/drivers/video/backlight/gta01_bl.c =================================================================== --- /dev/null +++ linux-2.6.21.3-moko/drivers/video/backlight/gta01_bl.c @@ -0,0 +1,288 @@ +/* + * Backlight Driver for FIC GTA01 (Neo1973) GSM Phone + * + * Copyright (C) 2006-2007 by OpenMoko, Inc. + * Author: Harald Welte + * All rights reserved. + * + * based on corgi_cl.c, Copyright (c) 2004-2006 Richard Purdie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * TODO: implement PWM, instead of simple on/off switching + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct backlight_properties gta01bl_prop; +static struct backlight_device *gta01_backlight_device; +static struct gta01bl_machinfo *bl_machinfo; + +static unsigned long gta01bl_flags; + +struct gta01bl_data { + int intensity; + struct mutex mutex; + struct clk *clk; +}; + +static struct gta01bl_data gta01bl; + +#define GTA01BL_SUSPENDED 0x01 +#define GTA01BL_BATTLOW 0x02 + +#define GTA01BL_FREQ 400 + +/* On the GTA01 / Neo1973, we use a 50 or 66MHz PCLK, which gives + * us a 6.25..8.25MHz DIV8 clock, which is further divided by a + * prescaler of 4, resulting in a 1.56..2.06MHz tick. This results in a + * minimum frequency of 24..31Hz. At 400Hz, we need to set the count + * to something like 3906..5156, providing us a way sufficient resolution + * for display brightness adjustment. */ + +static int gta01bl_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 (gta01bl_flags & GTA01BL_SUSPENDED) + intensity = 0; + if (gta01bl_flags & GTA01BL_BATTLOW) + intensity &= bl_machinfo->limit_mask; + + mutex_lock(>a01bl.mutex); +#ifdef GTA01_BACKLIGHT_ONOFF_ONLY + if (intensity) + s3c2410_gpio_setpin(GTA01_GPIO_BACKLIGHT, 1); + else + s3c2410_gpio_setpin(GTA01_GPIO_BACKLIGHT, 0); +#else + if (intensity == bd->props.max_brightness) { + s3c2410_gpio_setpin(GTA01_GPIO_BACKLIGHT, 1); + s3c2410_gpio_cfgpin(GTA01_GPIO_BACKLIGHT, S3C2410_GPIO_OUTPUT); + } else { + __raw_writel(intensity & 0xffff, S3C2410_TCMPB(0)); + s3c2410_gpio_cfgpin(GTA01_GPIO_BACKLIGHT, S3C2410_GPB0_TOUT0); + } +#endif + mutex_unlock(>a01bl.mutex); + + gta01bl.intensity = intensity; + + return 0; +} + +static void gta01bl_init_hw(void) +{ + unsigned long tcon, tcfg0, tcfg1, tcnt, pclk; + + pclk = clk_get_rate(gta01bl.clk); + + tcon = __raw_readl(S3C2410_TCON); + tcfg1 = __raw_readl(S3C2410_TCFG1); + tcfg0 = __raw_readl(S3C2410_TCFG0); + + tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK; + tcfg1 |= S3C2410_TCFG1_MUX0_DIV8; + + tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; + tcfg0 |= (4 - 1); + + tcnt = (pclk / 32) / GTA01BL_FREQ; + tcnt--; + + __raw_writel(tcfg1, S3C2410_TCFG1); + __raw_writel(tcfg0, S3C2410_TCFG0); + +#if 0 + __raw_writel(tcnt, S3C2410_TCNTB(0)); + __raw_writel(tcon, S3C2410_TCON); + __raw_writel(tcnt, S3C2410_TCNTB(0)); +#endif + + /* ensure timer is stopped */ + + tcon &= 0xffffff00; + tcon |= S3C2410_TCON_T0RELOAD; + tcon |= S3C2410_TCON_T0MANUALUPD; + + __raw_writel(tcnt, S3C2410_TCNTB(0)); + __raw_writel(tcnt, S3C2410_TCMPB(0)); + __raw_writel(tcon, S3C2410_TCON); + + /* start the timer */ + tcon |= S3C2410_TCON_T0START; + tcon &= ~S3C2410_TCON_T0MANUALUPD; + __raw_writel(tcon, S3C2410_TCON); + + gta01bl_prop.max_brightness = tcnt; +} + +#ifdef CONFIG_PM +static int gta01bl_suspend(struct platform_device *dev, pm_message_t state) +{ + gta01bl_flags |= GTA01BL_SUSPENDED; + gta01bl_send_intensity(gta01_backlight_device); + return 0; +} + +static int gta01bl_resume(struct platform_device *dev) +{ + mutex_lock(>a01bl.mutex); + gta01bl_init_hw(); + mutex_unlock(>a01bl.mutex); + + gta01bl_flags &= ~GTA01BL_SUSPENDED; + gta01bl_send_intensity(gta01_backlight_device); + return 0; +} +#else +#define gta01bl_suspend NULL +#define gta01bl_resume NULL +#endif + +static int gta01bl_get_intensity(struct backlight_device *bd) +{ + return gta01bl.intensity; +} + +static int gta01bl_set_intensity(struct backlight_device *bd) +{ + gta01bl_send_intensity(gta01_backlight_device); + return 0; +} + +/* + * Called when the battery is low to limit the backlight intensity. + * If limit==0 clear any limit, otherwise limit the intensity + */ +void gta01bl_limit_intensity(int limit) +{ + if (limit) + gta01bl_flags |= GTA01BL_BATTLOW; + else + gta01bl_flags &= ~GTA01BL_BATTLOW; + gta01bl_send_intensity(gta01_backlight_device); +} +EXPORT_SYMBOL(gta01bl_limit_intensity); + + +static struct backlight_ops gta01bl_ops = { + .get_brightness = gta01bl_get_intensity, + .update_status = gta01bl_set_intensity, +}; + +static int __init gta01bl_probe(struct platform_device *pdev) +{ + struct gta01bl_machinfo *machinfo = pdev->dev.platform_data; + +#ifdef GTA01_BACKLIGHT_ONOFF_ONLY + s3c2410_gpio_cfgpin(GTA01_GPIO_BACKLIGHT, S3C2410_GPIO_OUTPUT); + gta01bl_prop.max_brightness = 1; +#else + /* use s3c_device_timer0 for PWM */ + gta01bl.clk = clk_get(NULL, "timers"); + if (IS_ERR(gta01bl.clk)) + return PTR_ERR(gta01bl.clk); + + clk_enable(gta01bl.clk); + + gta01bl_init_hw(); +#endif + mutex_init(>a01bl.mutex); + + if (!machinfo->limit_mask) + machinfo->limit_mask = -1; + + gta01_backlight_device = backlight_device_register("gta01-bl", + &pdev->dev, NULL, + >a01bl_ops); + if (IS_ERR(gta01_backlight_device)) + return PTR_ERR(gta01_backlight_device); + + gta01bl_prop.power = FB_BLANK_UNBLANK; + gta01bl_prop.brightness = gta01bl_prop.max_brightness; + memcpy(>a01_backlight_device->props, + >a01bl_prop, sizeof(gta01bl_prop)); + gta01bl_send_intensity(gta01_backlight_device); + + printk("GTA01 Backlight Driver Initialized.\n"); + return 0; +} + +static int gta01bl_remove(struct platform_device *dev) +{ +#ifndef GTA01_BACKLIGHT_ONOFF_ONLY + unsigned long tcon; + + /* stop this timer */ + tcon = __raw_readl(S3C2410_TCON); + tcon &= 0xffffff00; + __raw_writel(tcon, S3C2410_TCON); + + clk_disable(gta01bl.clk); + clk_put(gta01bl.clk); +#endif + backlight_device_unregister(gta01_backlight_device); + mutex_destroy(>a01bl.mutex); + + printk("GTA01 Backlight Driver Unloaded, constant backlight\n"); + s3c2410_gpio_cfgpin(GTA01_GPIO_BACKLIGHT, S3C2410_GPIO_OUTPUT); + s3c2410_gpio_setpin(GTA01_GPIO_BACKLIGHT, 1); + + return 0; +} + +static struct platform_driver gta01bl_driver = { + .probe = gta01bl_probe, + .remove = gta01bl_remove, + .suspend = gta01bl_suspend, + .resume = gta01bl_resume, + .driver = { + .name = "gta01-bl", + }, +}; + +static int __init gta01bl_init(void) +{ + return platform_driver_register(>a01bl_driver); +} + +static void __exit gta01bl_exit(void) +{ + platform_driver_unregister(>a01bl_driver); +} + +module_init(gta01bl_init); +module_exit(gta01bl_exit); + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("FIC GTA01 (Neo1973) Backlight Driver"); +MODULE_LICENSE("GPL");