b42d05f2aaff60c1d8f6ab50d44f0a4b1eb62a49
[linux-3.10.git] / drivers / macintosh / via-pmu-backlight.c
1 /*
2  * Backlight code for via-pmu
3  *
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>
7  *
8  */
9
10 #include <asm/ptrace.h>
11 #include <linux/adb.h>
12 #include <linux/pmu.h>
13 #include <asm/backlight.h>
14 #include <asm/prom.h>
15
16 #define MAX_PMU_LEVEL 0xFF
17
18 static struct device_node *vias;
19 static struct backlight_properties pmu_backlight_data;
20
21 static int pmu_backlight_get_level_brightness(struct fb_info *info,
22                 int level)
23 {
24         int pmulevel;
25
26         /* Get and convert the value */
27         mutex_lock(&info->bl_mutex);
28         pmulevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
29         mutex_unlock(&info->bl_mutex);
30
31         if (pmulevel < 0)
32                 pmulevel = 0;
33         else if (pmulevel > MAX_PMU_LEVEL)
34                 pmulevel = MAX_PMU_LEVEL;
35
36         return pmulevel;
37 }
38
39 static int pmu_backlight_update_status(struct backlight_device *bd)
40 {
41         struct fb_info *info = class_get_devdata(&bd->class_dev);
42         struct adb_request req;
43         int pmulevel, level = bd->props->brightness;
44
45         if (vias == NULL)
46                 return -ENODEV;
47
48         if (bd->props->power != FB_BLANK_UNBLANK ||
49             bd->props->fb_blank != FB_BLANK_UNBLANK)
50                 level = 0;
51
52         pmulevel = pmu_backlight_get_level_brightness(info, level);
53
54         pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
55         pmu_wait_complete(&req);
56
57         pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
58                 PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF));
59         pmu_wait_complete(&req);
60
61         return 0;
62 }
63
64 static int pmu_backlight_get_brightness(struct backlight_device *bd)
65 {
66         return bd->props->brightness;
67 }
68
69 static struct backlight_properties pmu_backlight_data = {
70         .owner          = THIS_MODULE,
71         .get_brightness = pmu_backlight_get_brightness,
72         .update_status  = pmu_backlight_update_status,
73         .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
74 };
75
76 void __init pmu_backlight_init(struct device_node *in_vias)
77 {
78         struct backlight_device *bd;
79         struct fb_info *info;
80         char name[10];
81         int level, autosave;
82
83         vias = in_vias;
84
85         /* Special case for the old PowerBook since I can't test on it */
86         autosave =
87                 machine_is_compatible("AAPL,3400/2400") ||
88                 machine_is_compatible("AAPL,3500");
89
90         if (!autosave &&
91             !pmac_has_backlight_type("pmu") &&
92             !machine_is_compatible("AAPL,PowerBook1998") &&
93             !machine_is_compatible("PowerBook1,1"))
94                 return;
95
96         /* Actually, this is a hack, but I don't know of a better way
97          * to get the first framebuffer device.
98          */
99         info = registered_fb[0];
100         if (!info) {
101                 printk("pmubl: No framebuffer found\n");
102                 goto error;
103         }
104
105         snprintf(name, sizeof(name), "pmubl%d", info->node);
106
107         bd = backlight_device_register(name, info, &pmu_backlight_data);
108         if (IS_ERR(bd)) {
109                 printk("pmubl: Backlight registration failed\n");
110                 goto error;
111         }
112
113         mutex_lock(&info->bl_mutex);
114         info->bl_dev = bd;
115         fb_bl_default_curve(info, 0x7F, 0x46, 0x0E);
116         mutex_unlock(&info->bl_mutex);
117
118         level = pmu_backlight_data.max_brightness;
119
120         if (autosave) {
121                 /* read autosaved value if available */
122                 struct adb_request req;
123                 pmu_request(&req, NULL, 2, 0xd9, 0);
124                 pmu_wait_complete(&req);
125
126                 mutex_lock(&info->bl_mutex);
127                 level = pmac_backlight_curve_lookup(info,
128                                 (req.reply[0] >> 4) *
129                                 pmu_backlight_data.max_brightness / 15);
130                 mutex_unlock(&info->bl_mutex);
131         }
132
133         up(&bd->sem);
134         bd->props->brightness = level;
135         bd->props->power = FB_BLANK_UNBLANK;
136         bd->props->update_status(bd);
137         down(&bd->sem);
138
139         mutex_lock(&pmac_backlight_mutex);
140         if (!pmac_backlight)
141                 pmac_backlight = bd;
142         mutex_unlock(&pmac_backlight_mutex);
143
144         printk("pmubl: Backlight initialized (%s)\n", name);
145
146         return;
147
148 error:
149         return;
150 }