diff options
Diffstat (limited to 'drivers/video/backlight/locomolcd.c')
-rw-r--r-- | drivers/video/backlight/locomolcd.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c new file mode 100644 index 000000000..6c3ec4259 --- /dev/null +++ b/drivers/video/backlight/locomolcd.c @@ -0,0 +1,255 @@ +/* + * Backlight control code for Sharp Zaurus SL-5500 + * + * Copyright 2005 John Lenz <lenz@cs.wisc.edu> + * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-) + * GPL v2 + * + * This driver assumes single CPU. That's okay, because collie is + * slightly old hardware, and no one 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 const struct backlight_ops locomobl_data = { + .get_brightness = locomolcd_get_intensity, + .update_status = locomolcd_set_intensity, +}; + +#ifdef CONFIG_PM_SLEEP +static int locomolcd_suspend(struct device *dev) +{ + locomolcd_flags |= LOCOMOLCD_SUSPENDED; + locomolcd_set_intensity(locomolcd_bl_device); + return 0; +} + +static int locomolcd_resume(struct device *dev) +{ + locomolcd_flags &= ~LOCOMOLCD_SUSPENDED; + locomolcd_set_intensity(locomolcd_bl_device); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(locomolcd_pm_ops, locomolcd_suspend, locomolcd_resume); + +static int locomolcd_probe(struct locomo_dev *ldev) +{ + struct backlight_properties props; + 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); + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; + props.max_brightness = 4; + locomolcd_bl_device = backlight_device_register("locomo-bl", + &ldev->dev, NULL, + &locomobl_data, &props); + + if (IS_ERR(locomolcd_bl_device)) + return PTR_ERR(locomolcd_bl_device); + + /* Set up frontlight so that screen is readable */ + 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", + .pm = &locomolcd_pm_ops, + }, + .devid = LOCOMO_DEVID_BACKLIGHT, + .probe = locomolcd_probe, + .remove = locomolcd_remove, +}; + +static int __init locomolcd_init(void) +{ + return locomo_driver_register(&poodle_lcd_driver); +} + +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@ucw.cz>"); +MODULE_DESCRIPTION("Collie LCD driver"); +MODULE_LICENSE("GPL"); |