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