linux/arch/powerpc/platforms/powermac/backlight.c
<<
>>
Prefs
   1/*
   2 * Miscellaneous procedures for dealing with the PowerMac hardware.
   3 * Contains support for the backlight.
   4 *
   5 *   Copyright (C) 2000 Benjamin Herrenschmidt
   6 *   Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
   7 *
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/fb.h>
  12#include <linux/backlight.h>
  13#include <linux/adb.h>
  14#include <linux/pmu.h>
  15#include <asm/atomic.h>
  16#include <asm/prom.h>
  17#include <asm/backlight.h>
  18
  19#define OLD_BACKLIGHT_MAX 15
  20
  21static void pmac_backlight_key_worker(struct work_struct *work);
  22static void pmac_backlight_set_legacy_worker(struct work_struct *work);
  23
  24static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker);
  25static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker);
  26
  27/* Although these variables are used in interrupt context, it makes no sense to
  28 * protect them. No user is able to produce enough key events per second and
  29 * notice the errors that might happen.
  30 */
  31static int pmac_backlight_key_queued;
  32static int pmac_backlight_set_legacy_queued;
  33
  34/* The via-pmu code allows the backlight to be grabbed, in which case the
  35 * in-kernel control of the brightness needs to be disabled. This should
  36 * only be used by really old PowerBooks.
  37 */
  38static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0);
  39
  40/* Protect the pmac_backlight variable below.
  41   You should hold this lock when using the pmac_backlight pointer to
  42   prevent its potential removal. */
  43DEFINE_MUTEX(pmac_backlight_mutex);
  44
  45/* Main backlight storage
  46 *
  47 * Backlight drivers in this variable are required to have the "ops"
  48 * attribute set and to have an update_status function.
  49 *
  50 * We can only store one backlight here, but since Apple laptops have only one
  51 * internal display, it doesn't matter. Other backlight drivers can be used
  52 * independently.
  53 *
  54 */
  55struct backlight_device *pmac_backlight;
  56
  57int pmac_has_backlight_type(const char *type)
  58{
  59        struct device_node* bk_node = of_find_node_by_name(NULL, "backlight");
  60
  61        if (bk_node) {
  62                const char *prop = of_get_property(bk_node,
  63                                "backlight-control", NULL);
  64                if (prop && strncmp(prop, type, strlen(type)) == 0) {
  65                        of_node_put(bk_node);
  66                        return 1;
  67                }
  68                of_node_put(bk_node);
  69        }
  70
  71        return 0;
  72}
  73
  74int pmac_backlight_curve_lookup(struct fb_info *info, int value)
  75{
  76        int level = (FB_BACKLIGHT_LEVELS - 1);
  77
  78        if (info && info->bl_dev) {
  79                int i, max = 0;
  80
  81                /* Look for biggest value */
  82                for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
  83                        max = max((int)info->bl_curve[i], max);
  84
  85                /* Look for nearest value */
  86                for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
  87                        int diff = abs(info->bl_curve[i] - value);
  88                        if (diff < max) {
  89                                max = diff;
  90                                level = i;
  91                        }
  92                }
  93
  94        }
  95
  96        return level;
  97}
  98
  99static void pmac_backlight_key_worker(struct work_struct *work)
 100{
 101        if (atomic_read(&kernel_backlight_disabled))
 102                return;
 103
 104        mutex_lock(&pmac_backlight_mutex);
 105        if (pmac_backlight) {
 106                struct backlight_properties *props;
 107                int brightness;
 108
 109                props = &pmac_backlight->props;
 110
 111                brightness = props->brightness +
 112                        ((pmac_backlight_key_queued?-1:1) *
 113                         (props->max_brightness / 15));
 114
 115                if (brightness < 0)
 116                        brightness = 0;
 117                else if (brightness > props->max_brightness)
 118                        brightness = props->max_brightness;
 119
 120                props->brightness = brightness;
 121                backlight_update_status(pmac_backlight);
 122        }
 123        mutex_unlock(&pmac_backlight_mutex);
 124}
 125
 126/* This function is called in interrupt context */
 127void pmac_backlight_key(int direction)
 128{
 129        if (atomic_read(&kernel_backlight_disabled))
 130                return;
 131
 132        /* we can receive multiple interrupts here, but the scheduled work
 133         * will run only once, with the last value
 134         */
 135        pmac_backlight_key_queued = direction;
 136        schedule_work(&pmac_backlight_key_work);
 137}
 138
 139static int __pmac_backlight_set_legacy_brightness(int brightness)
 140{
 141        int error = -ENXIO;
 142
 143        mutex_lock(&pmac_backlight_mutex);
 144        if (pmac_backlight) {
 145                struct backlight_properties *props;
 146
 147                props = &pmac_backlight->props;
 148                props->brightness = brightness *
 149                        (props->max_brightness + 1) /
 150                        (OLD_BACKLIGHT_MAX + 1);
 151
 152                if (props->brightness > props->max_brightness)
 153                        props->brightness = props->max_brightness;
 154                else if (props->brightness < 0)
 155                        props->brightness = 0;
 156
 157                backlight_update_status(pmac_backlight);
 158
 159                error = 0;
 160        }
 161        mutex_unlock(&pmac_backlight_mutex);
 162
 163        return error;
 164}
 165
 166static void pmac_backlight_set_legacy_worker(struct work_struct *work)
 167{
 168        if (atomic_read(&kernel_backlight_disabled))
 169                return;
 170
 171        __pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued);
 172}
 173
 174/* This function is called in interrupt context */
 175void pmac_backlight_set_legacy_brightness_pmu(int brightness) {
 176        if (atomic_read(&kernel_backlight_disabled))
 177                return;
 178
 179        pmac_backlight_set_legacy_queued = brightness;
 180        schedule_work(&pmac_backlight_set_legacy_work);
 181}
 182
 183int pmac_backlight_set_legacy_brightness(int brightness)
 184{
 185        return __pmac_backlight_set_legacy_brightness(brightness);
 186}
 187
 188int pmac_backlight_get_legacy_brightness()
 189{
 190        int result = -ENXIO;
 191
 192        mutex_lock(&pmac_backlight_mutex);
 193        if (pmac_backlight) {
 194                struct backlight_properties *props;
 195
 196                props = &pmac_backlight->props;
 197
 198                result = props->brightness *
 199                        (OLD_BACKLIGHT_MAX + 1) /
 200                        (props->max_brightness + 1);
 201        }
 202        mutex_unlock(&pmac_backlight_mutex);
 203
 204        return result;
 205}
 206
 207void pmac_backlight_disable()
 208{
 209        atomic_inc(&kernel_backlight_disabled);
 210}
 211
 212void pmac_backlight_enable()
 213{
 214        atomic_dec(&kernel_backlight_disabled);
 215}
 216
 217EXPORT_SYMBOL_GPL(pmac_backlight);
 218EXPORT_SYMBOL_GPL(pmac_backlight_mutex);
 219EXPORT_SYMBOL_GPL(pmac_has_backlight_type);
 220
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.