1 // SPDX-License-Identifier: GPL-2.0
3 * Backlight code for via-pmu
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>
11 #include <asm/ptrace.h>
12 #include <linux/adb.h>
13 #include <linux/backlight.h>
14 #include <linux/pmu.h>
15 #include <asm/backlight.h>
17 #define MAX_PMU_LEVEL 0xFF
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
];
24 static void pmu_backlight_init_curve(u8 off
, u8 min
, u8 max
)
26 int i
, flat
, count
, range
= (max
- min
);
30 for (flat
= 1; flat
< (FB_BACKLIGHT_LEVELS
/ 16); ++flat
)
33 count
= FB_BACKLIGHT_LEVELS
* 15 / 16;
34 for (i
= 0; i
< count
; ++i
)
35 bl_curve
[flat
+ i
] = min
+ (range
* (i
+ 1) / count
);
38 static int pmu_backlight_curve_lookup(int value
)
40 int level
= (FB_BACKLIGHT_LEVELS
- 1);
43 /* Look for biggest value */
44 for (i
= 0; i
< FB_BACKLIGHT_LEVELS
; i
++)
45 max
= max((int)bl_curve
[i
], max
);
47 /* Look for nearest value */
48 for (i
= 0; i
< FB_BACKLIGHT_LEVELS
; i
++) {
49 int diff
= abs(bl_curve
[i
] - value
);
58 static int pmu_backlight_get_level_brightness(int level
)
62 /* Get and convert the value */
63 pmulevel
= bl_curve
[level
] * FB_BACKLIGHT_MAX
/ MAX_PMU_LEVEL
;
66 else if (pmulevel
> MAX_PMU_LEVEL
)
67 pmulevel
= MAX_PMU_LEVEL
;
72 static int __pmu_backlight_update_status(struct backlight_device
*bd
)
74 struct adb_request req
;
75 int level
= backlight_get_brightness(bd
);
78 int pmulevel
= pmu_backlight_get_level_brightness(level
);
80 pmu_request(&req
, NULL
, 2, PMU_BACKLIGHT_BRIGHT
, pmulevel
);
81 pmu_wait_complete(&req
);
83 pmu_request(&req
, NULL
, 2, PMU_POWER_CTRL
,
84 PMU_POW_BACKLIGHT
| PMU_POW_ON
);
85 pmu_wait_complete(&req
);
87 pmu_request(&req
, NULL
, 2, PMU_POWER_CTRL
,
88 PMU_POW_BACKLIGHT
| PMU_POW_OFF
);
89 pmu_wait_complete(&req
);
95 static int pmu_backlight_update_status(struct backlight_device
*bd
)
100 spin_lock_irqsave(&pmu_backlight_lock
, flags
);
101 /* Don't update brightness when sleeping */
103 rc
= __pmu_backlight_update_status(bd
);
104 spin_unlock_irqrestore(&pmu_backlight_lock
, flags
);
109 static const struct backlight_ops pmu_backlight_data
= {
110 .update_status
= pmu_backlight_update_status
,
115 void pmu_backlight_set_sleep(int sleep
)
119 spin_lock_irqsave(&pmu_backlight_lock
, flags
);
121 if (pmac_backlight
&& uses_pmu_bl
) {
123 struct adb_request req
;
125 pmu_request(&req
, NULL
, 2, PMU_POWER_CTRL
,
126 PMU_POW_BACKLIGHT
| PMU_POW_OFF
);
127 pmu_wait_complete(&req
);
129 __pmu_backlight_update_status(pmac_backlight
);
131 spin_unlock_irqrestore(&pmu_backlight_lock
, flags
);
133 #endif /* CONFIG_PM */
135 void __init
pmu_backlight_init(void)
137 struct backlight_properties props
;
138 struct backlight_device
*bd
;
142 /* Special case for the old PowerBook since I can't test on it */
144 of_machine_is_compatible("AAPL,3400/2400") ||
145 of_machine_is_compatible("AAPL,3500");
148 !pmac_has_backlight_type("pmu") &&
149 !of_machine_is_compatible("AAPL,PowerBook1998") &&
150 !of_machine_is_compatible("PowerBook1,1"))
153 snprintf(name
, sizeof(name
), "pmubl");
155 memset(&props
, 0, sizeof(struct backlight_properties
));
156 props
.type
= BACKLIGHT_PLATFORM
;
157 props
.max_brightness
= FB_BACKLIGHT_LEVELS
- 1;
158 bd
= backlight_device_register(name
, NULL
, NULL
, &pmu_backlight_data
,
161 printk(KERN_ERR
"PMU Backlight registration failed\n");
165 pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
167 level
= bd
->props
.max_brightness
;
170 /* read autosaved value if available */
171 struct adb_request req
;
172 pmu_request(&req
, NULL
, 2, 0xd9, 0);
173 pmu_wait_complete(&req
);
175 level
= pmu_backlight_curve_lookup(
176 (req
.reply
[0] >> 4) *
177 bd
->props
.max_brightness
/ 15);
180 bd
->props
.brightness
= level
;
181 bd
->props
.power
= BACKLIGHT_POWER_ON
;
182 backlight_update_status(bd
);
184 printk(KERN_INFO
"PMU Backlight initialized (%s)\n", name
);