2 * Backlight code for via-pmu
4 * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
5 * Copyright (C) 2001-2002 Benjamin Herrenschmidt
6 * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
10 #include <asm/ptrace.h>
11 #include <linux/adb.h>
12 #include <linux/pmu.h>
13 #include <asm/backlight.h>
16 #define MAX_PMU_LEVEL 0xFF
18 static struct backlight_ops pmu_backlight_data
;
19 static DEFINE_SPINLOCK(pmu_backlight_lock
);
21 static u8 bl_curve
[FB_BACKLIGHT_LEVELS
];
23 static void pmu_backlight_init_curve(u8 off
, u8 min
, u8 max
)
25 int i
, flat
, count
, range
= (max
- min
);
29 for (flat
= 1; flat
< (FB_BACKLIGHT_LEVELS
/ 16); ++flat
)
32 count
= FB_BACKLIGHT_LEVELS
* 15 / 16;
33 for (i
= 0; i
< count
; ++i
)
34 bl_curve
[flat
+ i
] = min
+ (range
* (i
+ 1) / count
);
37 static int pmu_backlight_curve_lookup(int value
)
39 int level
= (FB_BACKLIGHT_LEVELS
- 1);
42 /* Look for biggest value */
43 for (i
= 0; i
< FB_BACKLIGHT_LEVELS
; i
++)
44 max
= max((int)bl_curve
[i
], max
);
46 /* Look for nearest value */
47 for (i
= 0; i
< FB_BACKLIGHT_LEVELS
; i
++) {
48 int diff
= abs(bl_curve
[i
] - value
);
57 static int pmu_backlight_get_level_brightness(int level
)
61 /* Get and convert the value */
62 pmulevel
= bl_curve
[level
] * FB_BACKLIGHT_MAX
/ MAX_PMU_LEVEL
;
65 else if (pmulevel
> MAX_PMU_LEVEL
)
66 pmulevel
= MAX_PMU_LEVEL
;
71 static int __pmu_backlight_update_status(struct backlight_device
*bd
)
73 struct adb_request req
;
74 int level
= bd
->props
.brightness
;
77 if (bd
->props
.power
!= FB_BLANK_UNBLANK
||
78 bd
->props
.fb_blank
!= FB_BLANK_UNBLANK
)
82 int pmulevel
= pmu_backlight_get_level_brightness(level
);
84 pmu_request(&req
, NULL
, 2, PMU_BACKLIGHT_BRIGHT
, pmulevel
);
85 pmu_wait_complete(&req
);
87 pmu_request(&req
, NULL
, 2, PMU_POWER_CTRL
,
88 PMU_POW_BACKLIGHT
| PMU_POW_ON
);
89 pmu_wait_complete(&req
);
91 pmu_request(&req
, NULL
, 2, PMU_POWER_CTRL
,
92 PMU_POW_BACKLIGHT
| PMU_POW_OFF
);
93 pmu_wait_complete(&req
);
99 static int pmu_backlight_update_status(struct backlight_device
*bd
)
104 spin_lock_irqsave(&pmu_backlight_lock
, flags
);
105 /* Don't update brightness when sleeping */
107 rc
= __pmu_backlight_update_status(bd
);
108 spin_unlock_irqrestore(&pmu_backlight_lock
, flags
);
113 static int pmu_backlight_get_brightness(struct backlight_device
*bd
)
115 return bd
->props
.brightness
;
118 static struct backlight_ops pmu_backlight_data
= {
119 .get_brightness
= pmu_backlight_get_brightness
,
120 .update_status
= pmu_backlight_update_status
,
125 void pmu_backlight_set_sleep(int sleep
)
129 spin_lock_irqsave(&pmu_backlight_lock
, flags
);
131 if (pmac_backlight
) {
133 struct adb_request req
;
135 pmu_request(&req
, NULL
, 2, PMU_POWER_CTRL
,
136 PMU_POW_BACKLIGHT
| PMU_POW_OFF
);
137 pmu_wait_complete(&req
);
139 __pmu_backlight_update_status(pmac_backlight
);
141 spin_unlock_irqrestore(&pmu_backlight_lock
, flags
);
143 #endif /* CONFIG_PM */
145 void __init
pmu_backlight_init()
147 struct backlight_device
*bd
;
151 /* Special case for the old PowerBook since I can't test on it */
153 machine_is_compatible("AAPL,3400/2400") ||
154 machine_is_compatible("AAPL,3500");
157 !pmac_has_backlight_type("pmu") &&
158 !machine_is_compatible("AAPL,PowerBook1998") &&
159 !machine_is_compatible("PowerBook1,1"))
162 snprintf(name
, sizeof(name
), "pmubl");
164 bd
= backlight_device_register(name
, NULL
, NULL
, &pmu_backlight_data
);
166 printk(KERN_ERR
"PMU Backlight registration failed\n");
169 bd
->props
.max_brightness
= FB_BACKLIGHT_LEVELS
- 1;
170 pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
172 level
= bd
->props
.max_brightness
;
175 /* read autosaved value if available */
176 struct adb_request req
;
177 pmu_request(&req
, NULL
, 2, 0xd9, 0);
178 pmu_wait_complete(&req
);
180 level
= pmu_backlight_curve_lookup(
181 (req
.reply
[0] >> 4) *
182 bd
->props
.max_brightness
/ 15);
185 bd
->props
.brightness
= level
;
186 bd
->props
.power
= FB_BLANK_UNBLANK
;
187 backlight_update_status(bd
);
189 printk(KERN_INFO
"PMU Backlight initialized (%s)\n", name
);