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 unsigned 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
;
75 int level
= bd
->props
.brightness
;
77 spin_lock_irqsave(&pmu_backlight_lock
, flags
);
79 /* Don't update brightness when sleeping */
83 if (bd
->props
.power
!= FB_BLANK_UNBLANK
||
84 bd
->props
.fb_blank
!= FB_BLANK_UNBLANK
)
88 int pmulevel
= pmu_backlight_get_level_brightness(level
);
90 pmu_request(&req
, NULL
, 2, PMU_BACKLIGHT_BRIGHT
, pmulevel
);
91 pmu_wait_complete(&req
);
93 pmu_request(&req
, NULL
, 2, PMU_POWER_CTRL
,
94 PMU_POW_BACKLIGHT
| PMU_POW_ON
);
95 pmu_wait_complete(&req
);
97 pmu_request(&req
, NULL
, 2, PMU_POWER_CTRL
,
98 PMU_POW_BACKLIGHT
| PMU_POW_OFF
);
99 pmu_wait_complete(&req
);
103 spin_unlock_irqrestore(&pmu_backlight_lock
, flags
);
108 static int pmu_backlight_get_brightness(struct backlight_device
*bd
)
110 return bd
->props
.brightness
;
113 static struct backlight_ops pmu_backlight_data
= {
114 .get_brightness
= pmu_backlight_get_brightness
,
115 .update_status
= pmu_backlight_update_status
,
120 void pmu_backlight_set_sleep(int sleep
)
124 spin_lock_irqsave(&pmu_backlight_lock
, flags
);
126 spin_unlock_irqrestore(&pmu_backlight_lock
, flags
);
128 #endif /* CONFIG_PM */
130 void __init
pmu_backlight_init()
132 struct backlight_device
*bd
;
136 /* Special case for the old PowerBook since I can't test on it */
138 machine_is_compatible("AAPL,3400/2400") ||
139 machine_is_compatible("AAPL,3500");
142 !pmac_has_backlight_type("pmu") &&
143 !machine_is_compatible("AAPL,PowerBook1998") &&
144 !machine_is_compatible("PowerBook1,1"))
147 snprintf(name
, sizeof(name
), "pmubl");
149 bd
= backlight_device_register(name
, NULL
, NULL
, &pmu_backlight_data
);
151 printk("pmubl: Backlight registration failed\n");
154 bd
->props
.max_brightness
= FB_BACKLIGHT_LEVELS
- 1;
155 pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
157 level
= bd
->props
.max_brightness
;
160 /* read autosaved value if available */
161 struct adb_request req
;
162 pmu_request(&req
, NULL
, 2, 0xd9, 0);
163 pmu_wait_complete(&req
);
165 level
= pmu_backlight_curve_lookup(
166 (req
.reply
[0] >> 4) *
167 bd
->props
.max_brightness
/ 15);
170 bd
->props
.brightness
= level
;
171 bd
->props
.power
= FB_BLANK_UNBLANK
;
172 backlight_update_status(bd
);
174 printk("pmubl: Backlight initialized (%s)\n", name
);