Path: blob/master/arch/powerpc/platforms/powermac/backlight.c
10818 views
/*1* Miscellaneous procedures for dealing with the PowerMac hardware.2* Contains support for the backlight.3*4* Copyright (C) 2000 Benjamin Herrenschmidt5* Copyright (C) 2006 Michael Hanselmann <[email protected]>6*7*/89#include <linux/kernel.h>10#include <linux/fb.h>11#include <linux/backlight.h>12#include <linux/adb.h>13#include <linux/pmu.h>14#include <asm/atomic.h>15#include <asm/prom.h>16#include <asm/backlight.h>1718#define OLD_BACKLIGHT_MAX 151920static void pmac_backlight_key_worker(struct work_struct *work);21static void pmac_backlight_set_legacy_worker(struct work_struct *work);2223static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker);24static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker);2526/* Although these variables are used in interrupt context, it makes no sense to27* protect them. No user is able to produce enough key events per second and28* notice the errors that might happen.29*/30static int pmac_backlight_key_queued;31static int pmac_backlight_set_legacy_queued;3233/* The via-pmu code allows the backlight to be grabbed, in which case the34* in-kernel control of the brightness needs to be disabled. This should35* only be used by really old PowerBooks.36*/37static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0);3839/* Protect the pmac_backlight variable below.40You should hold this lock when using the pmac_backlight pointer to41prevent its potential removal. */42DEFINE_MUTEX(pmac_backlight_mutex);4344/* Main backlight storage45*46* Backlight drivers in this variable are required to have the "ops"47* attribute set and to have an update_status function.48*49* We can only store one backlight here, but since Apple laptops have only one50* internal display, it doesn't matter. Other backlight drivers can be used51* independently.52*53*/54struct backlight_device *pmac_backlight;5556int pmac_has_backlight_type(const char *type)57{58struct device_node* bk_node = of_find_node_by_name(NULL, "backlight");5960if (bk_node) {61const char *prop = of_get_property(bk_node,62"backlight-control", NULL);63if (prop && strncmp(prop, type, strlen(type)) == 0) {64of_node_put(bk_node);65return 1;66}67of_node_put(bk_node);68}6970return 0;71}7273int pmac_backlight_curve_lookup(struct fb_info *info, int value)74{75int level = (FB_BACKLIGHT_LEVELS - 1);7677if (info && info->bl_dev) {78int i, max = 0;7980/* Look for biggest value */81for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)82max = max((int)info->bl_curve[i], max);8384/* Look for nearest value */85for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {86int diff = abs(info->bl_curve[i] - value);87if (diff < max) {88max = diff;89level = i;90}91}9293}9495return level;96}9798static void pmac_backlight_key_worker(struct work_struct *work)99{100if (atomic_read(&kernel_backlight_disabled))101return;102103mutex_lock(&pmac_backlight_mutex);104if (pmac_backlight) {105struct backlight_properties *props;106int brightness;107108props = &pmac_backlight->props;109110brightness = props->brightness +111((pmac_backlight_key_queued?-1:1) *112(props->max_brightness / 15));113114if (brightness < 0)115brightness = 0;116else if (brightness > props->max_brightness)117brightness = props->max_brightness;118119props->brightness = brightness;120backlight_update_status(pmac_backlight);121}122mutex_unlock(&pmac_backlight_mutex);123}124125/* This function is called in interrupt context */126void pmac_backlight_key(int direction)127{128if (atomic_read(&kernel_backlight_disabled))129return;130131/* we can receive multiple interrupts here, but the scheduled work132* will run only once, with the last value133*/134pmac_backlight_key_queued = direction;135schedule_work(&pmac_backlight_key_work);136}137138static int __pmac_backlight_set_legacy_brightness(int brightness)139{140int error = -ENXIO;141142mutex_lock(&pmac_backlight_mutex);143if (pmac_backlight) {144struct backlight_properties *props;145146props = &pmac_backlight->props;147props->brightness = brightness *148(props->max_brightness + 1) /149(OLD_BACKLIGHT_MAX + 1);150151if (props->brightness > props->max_brightness)152props->brightness = props->max_brightness;153else if (props->brightness < 0)154props->brightness = 0;155156backlight_update_status(pmac_backlight);157158error = 0;159}160mutex_unlock(&pmac_backlight_mutex);161162return error;163}164165static void pmac_backlight_set_legacy_worker(struct work_struct *work)166{167if (atomic_read(&kernel_backlight_disabled))168return;169170__pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued);171}172173/* This function is called in interrupt context */174void pmac_backlight_set_legacy_brightness_pmu(int brightness) {175if (atomic_read(&kernel_backlight_disabled))176return;177178pmac_backlight_set_legacy_queued = brightness;179schedule_work(&pmac_backlight_set_legacy_work);180}181182int pmac_backlight_set_legacy_brightness(int brightness)183{184return __pmac_backlight_set_legacy_brightness(brightness);185}186187int pmac_backlight_get_legacy_brightness()188{189int result = -ENXIO;190191mutex_lock(&pmac_backlight_mutex);192if (pmac_backlight) {193struct backlight_properties *props;194195props = &pmac_backlight->props;196197result = props->brightness *198(OLD_BACKLIGHT_MAX + 1) /199(props->max_brightness + 1);200}201mutex_unlock(&pmac_backlight_mutex);202203return result;204}205206void pmac_backlight_disable()207{208atomic_inc(&kernel_backlight_disabled);209}210211void pmac_backlight_enable()212{213atomic_dec(&kernel_backlight_disabled);214}215216EXPORT_SYMBOL_GPL(pmac_backlight);217EXPORT_SYMBOL_GPL(pmac_backlight_mutex);218EXPORT_SYMBOL_GPL(pmac_has_backlight_type);219220221