123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- /*
- * Backlight code for via-pmu
- *
- * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
- * Copyright (C) 2001-2002 Benjamin Herrenschmidt
- * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
- *
- */
- #include <asm/ptrace.h>
- #include <linux/adb.h>
- #include <linux/pmu.h>
- #include <asm/backlight.h>
- #include <asm/prom.h>
- #define MAX_PMU_LEVEL 0xFF
- static const struct backlight_ops pmu_backlight_data;
- static DEFINE_SPINLOCK(pmu_backlight_lock);
- static int sleeping, uses_pmu_bl;
- static u8 bl_curve[FB_BACKLIGHT_LEVELS];
- static void pmu_backlight_init_curve(u8 off, u8 min, u8 max)
- {
- int i, flat, count, range = (max - min);
- bl_curve[0] = off;
- for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
- bl_curve[flat] = min;
- count = FB_BACKLIGHT_LEVELS * 15 / 16;
- for (i = 0; i < count; ++i)
- bl_curve[flat + i] = min + (range * (i + 1) / count);
- }
- static int pmu_backlight_curve_lookup(int value)
- {
- int level = (FB_BACKLIGHT_LEVELS - 1);
- int i, max = 0;
- /* Look for biggest value */
- for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
- max = max((int)bl_curve[i], max);
- /* Look for nearest value */
- for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
- int diff = abs(bl_curve[i] - value);
- if (diff < max) {
- max = diff;
- level = i;
- }
- }
- return level;
- }
- static int pmu_backlight_get_level_brightness(int level)
- {
- int pmulevel;
- /* Get and convert the value */
- pmulevel = bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
- if (pmulevel < 0)
- pmulevel = 0;
- else if (pmulevel > MAX_PMU_LEVEL)
- pmulevel = MAX_PMU_LEVEL;
- return pmulevel;
- }
- static int __pmu_backlight_update_status(struct backlight_device *bd)
- {
- struct adb_request req;
- int level = bd->props.brightness;
- if (bd->props.power != FB_BLANK_UNBLANK ||
- bd->props.fb_blank != FB_BLANK_UNBLANK)
- level = 0;
- if (level > 0) {
- int pmulevel = pmu_backlight_get_level_brightness(level);
- pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
- pmu_wait_complete(&req);
- pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | PMU_POW_ON);
- pmu_wait_complete(&req);
- } else {
- pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | PMU_POW_OFF);
- pmu_wait_complete(&req);
- }
- return 0;
- }
- static int pmu_backlight_update_status(struct backlight_device *bd)
- {
- unsigned long flags;
- int rc = 0;
- spin_lock_irqsave(&pmu_backlight_lock, flags);
- /* Don't update brightness when sleeping */
- if (!sleeping)
- rc = __pmu_backlight_update_status(bd);
- spin_unlock_irqrestore(&pmu_backlight_lock, flags);
- return rc;
- }
- static const struct backlight_ops pmu_backlight_data = {
- .update_status = pmu_backlight_update_status,
- };
- #ifdef CONFIG_PM
- void pmu_backlight_set_sleep(int sleep)
- {
- unsigned long flags;
- spin_lock_irqsave(&pmu_backlight_lock, flags);
- sleeping = sleep;
- if (pmac_backlight && uses_pmu_bl) {
- if (sleep) {
- struct adb_request req;
- pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | PMU_POW_OFF);
- pmu_wait_complete(&req);
- } else
- __pmu_backlight_update_status(pmac_backlight);
- }
- spin_unlock_irqrestore(&pmu_backlight_lock, flags);
- }
- #endif /* CONFIG_PM */
- void __init pmu_backlight_init()
- {
- struct backlight_properties props;
- struct backlight_device *bd;
- char name[10];
- int level, autosave;
- /* Special case for the old PowerBook since I can't test on it */
- autosave =
- of_machine_is_compatible("AAPL,3400/2400") ||
- of_machine_is_compatible("AAPL,3500");
- if (!autosave &&
- !pmac_has_backlight_type("pmu") &&
- !of_machine_is_compatible("AAPL,PowerBook1998") &&
- !of_machine_is_compatible("PowerBook1,1"))
- return;
- snprintf(name, sizeof(name), "pmubl");
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_PLATFORM;
- props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
- bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data,
- &props);
- if (IS_ERR(bd)) {
- printk(KERN_ERR "PMU Backlight registration failed\n");
- return;
- }
- uses_pmu_bl = 1;
- pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
- level = bd->props.max_brightness;
- if (autosave) {
- /* read autosaved value if available */
- struct adb_request req;
- pmu_request(&req, NULL, 2, 0xd9, 0);
- pmu_wait_complete(&req);
- level = pmu_backlight_curve_lookup(
- (req.reply[0] >> 4) *
- bd->props.max_brightness / 15);
- }
- bd->props.brightness = level;
- bd->props.power = FB_BLANK_UNBLANK;
- backlight_update_status(bd);
- printk(KERN_INFO "PMU Backlight initialized (%s)\n", name);
- }
|