root/drivers/macintosh/via-pmu-backlight.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pmu_backlight_init_curve
  2. pmu_backlight_curve_lookup
  3. pmu_backlight_get_level_brightness
  4. __pmu_backlight_update_status
  5. pmu_backlight_update_status
  6. pmu_backlight_set_sleep
  7. pmu_backlight_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Backlight code for via-pmu
   4  *
   5  * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
   6  * Copyright (C) 2001-2002 Benjamin Herrenschmidt
   7  * Copyright (C) 2006      Michael Hanselmann <linux-kernel@hansmi.ch>
   8  *
   9  */
  10 
  11 #include <asm/ptrace.h>
  12 #include <linux/adb.h>
  13 #include <linux/pmu.h>
  14 #include <asm/backlight.h>
  15 #include <asm/prom.h>
  16 
  17 #define MAX_PMU_LEVEL 0xFF
  18 
  19 static const struct backlight_ops pmu_backlight_data;
  20 static DEFINE_SPINLOCK(pmu_backlight_lock);
  21 static int sleeping, uses_pmu_bl;
  22 static u8 bl_curve[FB_BACKLIGHT_LEVELS];
  23 
  24 static void pmu_backlight_init_curve(u8 off, u8 min, u8 max)
  25 {
  26         int i, flat, count, range = (max - min);
  27 
  28         bl_curve[0] = off;
  29 
  30         for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
  31                 bl_curve[flat] = min;
  32 
  33         count = FB_BACKLIGHT_LEVELS * 15 / 16;
  34         for (i = 0; i < count; ++i)
  35                 bl_curve[flat + i] = min + (range * (i + 1) / count);
  36 }
  37 
  38 static int pmu_backlight_curve_lookup(int value)
  39 {
  40         int level = (FB_BACKLIGHT_LEVELS - 1);
  41         int i, max = 0;
  42 
  43         /* Look for biggest value */
  44         for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
  45                 max = max((int)bl_curve[i], max);
  46 
  47         /* Look for nearest value */
  48         for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
  49                 int diff = abs(bl_curve[i] - value);
  50                 if (diff < max) {
  51                         max = diff;
  52                         level = i;
  53                 }
  54         }
  55         return level;
  56 }
  57 
  58 static int pmu_backlight_get_level_brightness(int level)
  59 {
  60         int pmulevel;
  61 
  62         /* Get and convert the value */
  63         pmulevel = bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
  64         if (pmulevel < 0)
  65                 pmulevel = 0;
  66         else if (pmulevel > MAX_PMU_LEVEL)
  67                 pmulevel = MAX_PMU_LEVEL;
  68 
  69         return pmulevel;
  70 }
  71 
  72 static int __pmu_backlight_update_status(struct backlight_device *bd)
  73 {
  74         struct adb_request req;
  75         int level = bd->props.brightness;
  76 
  77 
  78         if (bd->props.power != FB_BLANK_UNBLANK ||
  79             bd->props.fb_blank != FB_BLANK_UNBLANK)
  80                 level = 0;
  81 
  82         if (level > 0) {
  83                 int pmulevel = pmu_backlight_get_level_brightness(level);
  84 
  85                 pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
  86                 pmu_wait_complete(&req);
  87 
  88                 pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
  89                         PMU_POW_BACKLIGHT | PMU_POW_ON);
  90                 pmu_wait_complete(&req);
  91         } else {
  92                 pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
  93                         PMU_POW_BACKLIGHT | PMU_POW_OFF);
  94                 pmu_wait_complete(&req);
  95         }
  96 
  97         return 0;
  98 }
  99 
 100 static int pmu_backlight_update_status(struct backlight_device *bd)
 101 {
 102         unsigned long flags;
 103         int rc = 0;
 104 
 105         spin_lock_irqsave(&pmu_backlight_lock, flags);
 106         /* Don't update brightness when sleeping */
 107         if (!sleeping)
 108                 rc = __pmu_backlight_update_status(bd);
 109         spin_unlock_irqrestore(&pmu_backlight_lock, flags);
 110         return rc;
 111 }
 112 
 113 
 114 static const struct backlight_ops pmu_backlight_data = {
 115         .update_status  = pmu_backlight_update_status,
 116 
 117 };
 118 
 119 #ifdef CONFIG_PM
 120 void pmu_backlight_set_sleep(int sleep)
 121 {
 122         unsigned long flags;
 123 
 124         spin_lock_irqsave(&pmu_backlight_lock, flags);
 125         sleeping = sleep;
 126         if (pmac_backlight && uses_pmu_bl) {
 127                 if (sleep) {
 128                         struct adb_request req;
 129 
 130                         pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
 131                                     PMU_POW_BACKLIGHT | PMU_POW_OFF);
 132                         pmu_wait_complete(&req);
 133                 } else
 134                         __pmu_backlight_update_status(pmac_backlight);
 135         }
 136         spin_unlock_irqrestore(&pmu_backlight_lock, flags);
 137 }
 138 #endif /* CONFIG_PM */
 139 
 140 void __init pmu_backlight_init(void)
 141 {
 142         struct backlight_properties props;
 143         struct backlight_device *bd;
 144         char name[10];
 145         int level, autosave;
 146 
 147         /* Special case for the old PowerBook since I can't test on it */
 148         autosave =
 149                 of_machine_is_compatible("AAPL,3400/2400") ||
 150                 of_machine_is_compatible("AAPL,3500");
 151 
 152         if (!autosave &&
 153             !pmac_has_backlight_type("pmu") &&
 154             !of_machine_is_compatible("AAPL,PowerBook1998") &&
 155             !of_machine_is_compatible("PowerBook1,1"))
 156                 return;
 157 
 158         snprintf(name, sizeof(name), "pmubl");
 159 
 160         memset(&props, 0, sizeof(struct backlight_properties));
 161         props.type = BACKLIGHT_PLATFORM;
 162         props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
 163         bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data,
 164                                        &props);
 165         if (IS_ERR(bd)) {
 166                 printk(KERN_ERR "PMU Backlight registration failed\n");
 167                 return;
 168         }
 169         uses_pmu_bl = 1;
 170         pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
 171 
 172         level = bd->props.max_brightness;
 173 
 174         if (autosave) {
 175                 /* read autosaved value if available */
 176                 struct adb_request req;
 177                 pmu_request(&req, NULL, 2, 0xd9, 0);
 178                 pmu_wait_complete(&req);
 179 
 180                 level = pmu_backlight_curve_lookup(
 181                                 (req.reply[0] >> 4) *
 182                                 bd->props.max_brightness / 15);
 183         }
 184 
 185         bd->props.brightness = level;
 186         bd->props.power = FB_BLANK_UNBLANK;
 187         backlight_update_status(bd);
 188 
 189         printk(KERN_INFO "PMU Backlight initialized (%s)\n", name);
 190 }

/* [<][>][^][v][top][bottom][index][help] */