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 } 151