106c6f900SAndriy Skulysh /*
206c6f900SAndriy Skulysh * Backlight Driver for HP Jornada 680
306c6f900SAndriy Skulysh *
406c6f900SAndriy Skulysh * Copyright (c) 2005 Andriy Skulysh
506c6f900SAndriy Skulysh *
606c6f900SAndriy Skulysh * Based on Sharp's Corgi Backlight Driver
706c6f900SAndriy Skulysh *
806c6f900SAndriy Skulysh * This file is subject to the terms and conditions of the GNU General Public
906c6f900SAndriy Skulysh * License. See the file "COPYING" in the main directory of this archive
1006c6f900SAndriy Skulysh * for more details.
1106c6f900SAndriy Skulysh */
1206c6f900SAndriy Skulysh
1306c6f900SAndriy Skulysh #include <linux/module.h>
1406c6f900SAndriy Skulysh #include <linux/kernel.h>
1506c6f900SAndriy Skulysh #include <linux/init.h>
165f27a27bSRichard Purdie #include <linux/platform_device.h>
1706c6f900SAndriy Skulysh #include <linux/spinlock.h>
1806c6f900SAndriy Skulysh #include <linux/fb.h>
1906c6f900SAndriy Skulysh #include <linux/backlight.h>
2006c6f900SAndriy Skulysh
21193f3c2fSPaul Mundt #include <cpu/dac.h>
227639a454SPaul Mundt #include <mach/hp6xx.h>
23848dd265SAndriy Skulysh #include <asm/hd64461.h>
2406c6f900SAndriy Skulysh
2506c6f900SAndriy Skulysh #define HP680_MAX_INTENSITY 255
2606c6f900SAndriy Skulysh #define HP680_DEFAULT_INTENSITY 10
2706c6f900SAndriy Skulysh
285f27a27bSRichard Purdie static int hp680bl_suspended;
29ff10b074SJingoo Han static int current_intensity;
3034af946aSIngo Molnar static DEFINE_SPINLOCK(bl_lock);
3106c6f900SAndriy Skulysh
hp680bl_send_intensity(struct backlight_device * bd)325f27a27bSRichard Purdie static void hp680bl_send_intensity(struct backlight_device *bd)
3306c6f900SAndriy Skulysh {
3406c6f900SAndriy Skulysh unsigned long flags;
355f27a27bSRichard Purdie u16 v;
3651d53e5bSSam Ravnborg int intensity = backlight_get_brightness(bd);
3706c6f900SAndriy Skulysh
385f27a27bSRichard Purdie if (hp680bl_suspended)
3906c6f900SAndriy Skulysh intensity = 0;
4006c6f900SAndriy Skulysh
4106c6f900SAndriy Skulysh spin_lock_irqsave(&bl_lock, flags);
425f27a27bSRichard Purdie if (intensity && current_intensity == 0) {
4306c6f900SAndriy Skulysh sh_dac_enable(DAC_LCD_BRIGHTNESS);
4406c6f900SAndriy Skulysh v = inw(HD64461_GPBDR);
4506c6f900SAndriy Skulysh v &= ~HD64461_GPBDR_LCDOFF;
4606c6f900SAndriy Skulysh outw(v, HD64461_GPBDR);
475f27a27bSRichard Purdie sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
485f27a27bSRichard Purdie } else if (intensity == 0 && current_intensity != 0) {
495f27a27bSRichard Purdie sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
505f27a27bSRichard Purdie sh_dac_disable(DAC_LCD_BRIGHTNESS);
515f27a27bSRichard Purdie v = inw(HD64461_GPBDR);
525f27a27bSRichard Purdie v |= HD64461_GPBDR_LCDOFF;
535f27a27bSRichard Purdie outw(v, HD64461_GPBDR);
545f27a27bSRichard Purdie } else if (intensity) {
555f27a27bSRichard Purdie sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
5606c6f900SAndriy Skulysh }
575f27a27bSRichard Purdie spin_unlock_irqrestore(&bl_lock, flags);
585f27a27bSRichard Purdie
595f27a27bSRichard Purdie current_intensity = intensity;
6006c6f900SAndriy Skulysh }
6106c6f900SAndriy Skulysh
625f27a27bSRichard Purdie
63b55bb78dSJingoo Han #ifdef CONFIG_PM_SLEEP
hp680bl_suspend(struct device * dev)64b55bb78dSJingoo Han static int hp680bl_suspend(struct device *dev)
6506c6f900SAndriy Skulysh {
66b55bb78dSJingoo Han struct backlight_device *bd = dev_get_drvdata(dev);
67a8db3c19SRichard Purdie
685f27a27bSRichard Purdie hp680bl_suspended = 1;
69a8db3c19SRichard Purdie hp680bl_send_intensity(bd);
7006c6f900SAndriy Skulysh return 0;
7106c6f900SAndriy Skulysh }
7206c6f900SAndriy Skulysh
hp680bl_resume(struct device * dev)73b55bb78dSJingoo Han static int hp680bl_resume(struct device *dev)
7406c6f900SAndriy Skulysh {
75b55bb78dSJingoo Han struct backlight_device *bd = dev_get_drvdata(dev);
76a8db3c19SRichard Purdie
775f27a27bSRichard Purdie hp680bl_suspended = 0;
78a8db3c19SRichard Purdie hp680bl_send_intensity(bd);
7906c6f900SAndriy Skulysh return 0;
8006c6f900SAndriy Skulysh }
8106c6f900SAndriy Skulysh #endif
8206c6f900SAndriy Skulysh
83b55bb78dSJingoo Han static SIMPLE_DEV_PM_OPS(hp680bl_pm_ops, hp680bl_suspend, hp680bl_resume);
84b55bb78dSJingoo Han
hp680bl_set_intensity(struct backlight_device * bd)855f27a27bSRichard Purdie static int hp680bl_set_intensity(struct backlight_device *bd)
8606c6f900SAndriy Skulysh {
875f27a27bSRichard Purdie hp680bl_send_intensity(bd);
8806c6f900SAndriy Skulysh return 0;
8906c6f900SAndriy Skulysh }
9006c6f900SAndriy Skulysh
hp680bl_get_intensity(struct backlight_device * bd)9106c6f900SAndriy Skulysh static int hp680bl_get_intensity(struct backlight_device *bd)
9206c6f900SAndriy Skulysh {
9306c6f900SAndriy Skulysh return current_intensity;
9406c6f900SAndriy Skulysh }
9506c6f900SAndriy Skulysh
969905a43bSEmese Revfy static const struct backlight_ops hp680bl_ops = {
9706c6f900SAndriy Skulysh .get_brightness = hp680bl_get_intensity,
985f27a27bSRichard Purdie .update_status = hp680bl_set_intensity,
9906c6f900SAndriy Skulysh };
10006c6f900SAndriy Skulysh
hp680bl_probe(struct platform_device * pdev)1011b9e450dSBill Pemberton static int hp680bl_probe(struct platform_device *pdev)
10206c6f900SAndriy Skulysh {
103a19a6ee6SMatthew Garrett struct backlight_properties props;
104a8db3c19SRichard Purdie struct backlight_device *bd;
10506c6f900SAndriy Skulysh
106a19a6ee6SMatthew Garrett memset(&props, 0, sizeof(struct backlight_properties));
107bb7ca747SMatthew Garrett props.type = BACKLIGHT_RAW;
108a19a6ee6SMatthew Garrett props.max_brightness = HP680_MAX_INTENSITY;
1090561c179SJingoo Han bd = devm_backlight_device_register(&pdev->dev, "hp680-bl", &pdev->dev,
1100561c179SJingoo Han NULL, &hp680bl_ops, &props);
111a8db3c19SRichard Purdie if (IS_ERR(bd))
112a8db3c19SRichard Purdie return PTR_ERR(bd);
113a8db3c19SRichard Purdie
114a8db3c19SRichard Purdie platform_set_drvdata(pdev, bd);
115a8db3c19SRichard Purdie
116599a52d1SRichard Purdie bd->props.brightness = HP680_DEFAULT_INTENSITY;
117a8db3c19SRichard Purdie hp680bl_send_intensity(bd);
11806c6f900SAndriy Skulysh
11906c6f900SAndriy Skulysh return 0;
12006c6f900SAndriy Skulysh }
12106c6f900SAndriy Skulysh
hp680bl_remove(struct platform_device * pdev)122*7150f8c2SUwe Kleine-König static void hp680bl_remove(struct platform_device *pdev)
12306c6f900SAndriy Skulysh {
124a8db3c19SRichard Purdie struct backlight_device *bd = platform_get_drvdata(pdev);
125a8db3c19SRichard Purdie
126eb650d67SKristoffer Ericson bd->props.brightness = 0;
127eb650d67SKristoffer Ericson bd->props.power = 0;
128a8db3c19SRichard Purdie hp680bl_send_intensity(bd);
12906c6f900SAndriy Skulysh }
13006c6f900SAndriy Skulysh
1315f27a27bSRichard Purdie static struct platform_driver hp680bl_driver = {
13206c6f900SAndriy Skulysh .probe = hp680bl_probe,
133*7150f8c2SUwe Kleine-König .remove_new = hp680bl_remove,
1345f27a27bSRichard Purdie .driver = {
1355f27a27bSRichard Purdie .name = "hp680-bl",
136b55bb78dSJingoo Han .pm = &hp680bl_pm_ops,
1375f27a27bSRichard Purdie },
13806c6f900SAndriy Skulysh };
13906c6f900SAndriy Skulysh
1405f27a27bSRichard Purdie static struct platform_device *hp680bl_device;
14106c6f900SAndriy Skulysh
hp680bl_init(void)14206c6f900SAndriy Skulysh static int __init hp680bl_init(void)
14306c6f900SAndriy Skulysh {
14406c6f900SAndriy Skulysh int ret;
14506c6f900SAndriy Skulysh
1465f27a27bSRichard Purdie ret = platform_driver_register(&hp680bl_driver);
1473bcdcc0eSAkinobu Mita if (ret)
14806c6f900SAndriy Skulysh return ret;
1493bcdcc0eSAkinobu Mita hp680bl_device = platform_device_register_simple("hp680-bl", -1,
1503bcdcc0eSAkinobu Mita NULL, 0);
1513bcdcc0eSAkinobu Mita if (IS_ERR(hp680bl_device)) {
1523bcdcc0eSAkinobu Mita platform_driver_unregister(&hp680bl_driver);
1533bcdcc0eSAkinobu Mita return PTR_ERR(hp680bl_device);
1543bcdcc0eSAkinobu Mita }
1553bcdcc0eSAkinobu Mita return 0;
15606c6f900SAndriy Skulysh }
15706c6f900SAndriy Skulysh
hp680bl_exit(void)15806c6f900SAndriy Skulysh static void __exit hp680bl_exit(void)
15906c6f900SAndriy Skulysh {
1605f27a27bSRichard Purdie platform_device_unregister(hp680bl_device);
1615f27a27bSRichard Purdie platform_driver_unregister(&hp680bl_driver);
16206c6f900SAndriy Skulysh }
16306c6f900SAndriy Skulysh
16406c6f900SAndriy Skulysh module_init(hp680bl_init);
16506c6f900SAndriy Skulysh module_exit(hp680bl_exit);
16606c6f900SAndriy Skulysh
167848dd265SAndriy Skulysh MODULE_AUTHOR("Andriy Skulysh <askulysh@gmail.com>");
16806c6f900SAndriy Skulysh MODULE_DESCRIPTION("HP Jornada 680 Backlight Driver");
16906c6f900SAndriy Skulysh MODULE_LICENSE("GPL");
170