0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <asm/ptrace.h>
0012 #include <linux/adb.h>
0013 #include <linux/pmu.h>
0014 #include <asm/backlight.h>
0015
0016 #define MAX_PMU_LEVEL 0xFF
0017
0018 static const struct backlight_ops pmu_backlight_data;
0019 static DEFINE_SPINLOCK(pmu_backlight_lock);
0020 static int sleeping, uses_pmu_bl;
0021 static u8 bl_curve[FB_BACKLIGHT_LEVELS];
0022
0023 static void pmu_backlight_init_curve(u8 off, u8 min, u8 max)
0024 {
0025 int i, flat, count, range = (max - min);
0026
0027 bl_curve[0] = off;
0028
0029 for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
0030 bl_curve[flat] = min;
0031
0032 count = FB_BACKLIGHT_LEVELS * 15 / 16;
0033 for (i = 0; i < count; ++i)
0034 bl_curve[flat + i] = min + (range * (i + 1) / count);
0035 }
0036
0037 static int pmu_backlight_curve_lookup(int value)
0038 {
0039 int level = (FB_BACKLIGHT_LEVELS - 1);
0040 int i, max = 0;
0041
0042
0043 for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
0044 max = max((int)bl_curve[i], max);
0045
0046
0047 for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
0048 int diff = abs(bl_curve[i] - value);
0049 if (diff < max) {
0050 max = diff;
0051 level = i;
0052 }
0053 }
0054 return level;
0055 }
0056
0057 static int pmu_backlight_get_level_brightness(int level)
0058 {
0059 int pmulevel;
0060
0061
0062 pmulevel = bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
0063 if (pmulevel < 0)
0064 pmulevel = 0;
0065 else if (pmulevel > MAX_PMU_LEVEL)
0066 pmulevel = MAX_PMU_LEVEL;
0067
0068 return pmulevel;
0069 }
0070
0071 static int __pmu_backlight_update_status(struct backlight_device *bd)
0072 {
0073 struct adb_request req;
0074 int level = bd->props.brightness;
0075
0076
0077 if (bd->props.power != FB_BLANK_UNBLANK ||
0078 bd->props.fb_blank != FB_BLANK_UNBLANK)
0079 level = 0;
0080
0081 if (level > 0) {
0082 int pmulevel = pmu_backlight_get_level_brightness(level);
0083
0084 pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
0085 pmu_wait_complete(&req);
0086
0087 pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
0088 PMU_POW_BACKLIGHT | PMU_POW_ON);
0089 pmu_wait_complete(&req);
0090 } else {
0091 pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
0092 PMU_POW_BACKLIGHT | PMU_POW_OFF);
0093 pmu_wait_complete(&req);
0094 }
0095
0096 return 0;
0097 }
0098
0099 static int pmu_backlight_update_status(struct backlight_device *bd)
0100 {
0101 unsigned long flags;
0102 int rc = 0;
0103
0104 spin_lock_irqsave(&pmu_backlight_lock, flags);
0105
0106 if (!sleeping)
0107 rc = __pmu_backlight_update_status(bd);
0108 spin_unlock_irqrestore(&pmu_backlight_lock, flags);
0109 return rc;
0110 }
0111
0112
0113 static const struct backlight_ops pmu_backlight_data = {
0114 .update_status = pmu_backlight_update_status,
0115
0116 };
0117
0118 #ifdef CONFIG_PM
0119 void pmu_backlight_set_sleep(int sleep)
0120 {
0121 unsigned long flags;
0122
0123 spin_lock_irqsave(&pmu_backlight_lock, flags);
0124 sleeping = sleep;
0125 if (pmac_backlight && uses_pmu_bl) {
0126 if (sleep) {
0127 struct adb_request req;
0128
0129 pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
0130 PMU_POW_BACKLIGHT | PMU_POW_OFF);
0131 pmu_wait_complete(&req);
0132 } else
0133 __pmu_backlight_update_status(pmac_backlight);
0134 }
0135 spin_unlock_irqrestore(&pmu_backlight_lock, flags);
0136 }
0137 #endif
0138
0139 void __init pmu_backlight_init(void)
0140 {
0141 struct backlight_properties props;
0142 struct backlight_device *bd;
0143 char name[10];
0144 int level, autosave;
0145
0146
0147 autosave =
0148 of_machine_is_compatible("AAPL,3400/2400") ||
0149 of_machine_is_compatible("AAPL,3500");
0150
0151 if (!autosave &&
0152 !pmac_has_backlight_type("pmu") &&
0153 !of_machine_is_compatible("AAPL,PowerBook1998") &&
0154 !of_machine_is_compatible("PowerBook1,1"))
0155 return;
0156
0157 snprintf(name, sizeof(name), "pmubl");
0158
0159 memset(&props, 0, sizeof(struct backlight_properties));
0160 props.type = BACKLIGHT_PLATFORM;
0161 props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
0162 bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data,
0163 &props);
0164 if (IS_ERR(bd)) {
0165 printk(KERN_ERR "PMU Backlight registration failed\n");
0166 return;
0167 }
0168 uses_pmu_bl = 1;
0169 pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
0170
0171 level = bd->props.max_brightness;
0172
0173 if (autosave) {
0174
0175 struct adb_request req;
0176 pmu_request(&req, NULL, 2, 0xd9, 0);
0177 pmu_wait_complete(&req);
0178
0179 level = pmu_backlight_curve_lookup(
0180 (req.reply[0] >> 4) *
0181 bd->props.max_brightness / 15);
0182 }
0183
0184 bd->props.brightness = level;
0185 bd->props.power = FB_BLANK_UNBLANK;
0186 backlight_update_status(bd);
0187
0188 printk(KERN_INFO "PMU Backlight initialized (%s)\n", name);
0189 }