^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Backlight Driver for HP Jornada 680
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2005 Andriy Skulysh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Based on Sharp's Corgi Backlight Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <cpu/dac.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <mach/hp6xx.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/hd64461.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define HP680_MAX_INTENSITY 255
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define HP680_DEFAULT_INTENSITY 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static int hp680bl_suspended;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static int current_intensity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static DEFINE_SPINLOCK(bl_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static void hp680bl_send_intensity(struct backlight_device *bd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) u16 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) int intensity = backlight_get_brightness(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (hp680bl_suspended)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) intensity = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) spin_lock_irqsave(&bl_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (intensity && current_intensity == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) sh_dac_enable(DAC_LCD_BRIGHTNESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) v = inw(HD64461_GPBDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) v &= ~HD64461_GPBDR_LCDOFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) outw(v, HD64461_GPBDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) } else if (intensity == 0 && current_intensity != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) sh_dac_disable(DAC_LCD_BRIGHTNESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) v = inw(HD64461_GPBDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) v |= HD64461_GPBDR_LCDOFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) outw(v, HD64461_GPBDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) } else if (intensity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) spin_unlock_irqrestore(&bl_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) current_intensity = intensity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int hp680bl_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct backlight_device *bd = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) hp680bl_suspended = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) hp680bl_send_intensity(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int hp680bl_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct backlight_device *bd = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) hp680bl_suspended = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) hp680bl_send_intensity(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static SIMPLE_DEV_PM_OPS(hp680bl_pm_ops, hp680bl_suspend, hp680bl_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int hp680bl_set_intensity(struct backlight_device *bd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) hp680bl_send_intensity(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static int hp680bl_get_intensity(struct backlight_device *bd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return current_intensity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static const struct backlight_ops hp680bl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .get_brightness = hp680bl_get_intensity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .update_status = hp680bl_set_intensity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static int hp680bl_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct backlight_properties props;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct backlight_device *bd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) memset(&props, 0, sizeof(struct backlight_properties));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) props.type = BACKLIGHT_RAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) props.max_brightness = HP680_MAX_INTENSITY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) bd = devm_backlight_device_register(&pdev->dev, "hp680-bl", &pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) NULL, &hp680bl_ops, &props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (IS_ERR(bd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return PTR_ERR(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) platform_set_drvdata(pdev, bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) bd->props.brightness = HP680_DEFAULT_INTENSITY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) hp680bl_send_intensity(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int hp680bl_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct backlight_device *bd = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) bd->props.brightness = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) bd->props.power = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) hp680bl_send_intensity(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static struct platform_driver hp680bl_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) .probe = hp680bl_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .remove = hp680bl_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .name = "hp680-bl",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .pm = &hp680bl_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static struct platform_device *hp680bl_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static int __init hp680bl_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) ret = platform_driver_register(&hp680bl_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) hp680bl_device = platform_device_register_simple("hp680-bl", -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (IS_ERR(hp680bl_device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) platform_driver_unregister(&hp680bl_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return PTR_ERR(hp680bl_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static void __exit hp680bl_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) platform_device_unregister(hp680bl_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) platform_driver_unregister(&hp680bl_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) module_init(hp680bl_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) module_exit(hp680bl_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) MODULE_AUTHOR("Andriy Skulysh <askulysh@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) MODULE_DESCRIPTION("HP Jornada 680 Backlight Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) MODULE_LICENSE("GPL");