brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · 26bd9ed Raw
186 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Backlight code for via-pmu4 *5 * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.6 * Copyright (C) 2001-2002 Benjamin Herrenschmidt7 * Copyright (C) 2006      Michael Hanselmann <linux-kernel@hansmi.ch>8 *9 */10 11#include <asm/ptrace.h>12#include <linux/adb.h>13#include <linux/backlight.h>14#include <linux/pmu.h>15#include <asm/backlight.h>16 17#define MAX_PMU_LEVEL 0xFF18 19static const struct backlight_ops pmu_backlight_data;20static DEFINE_SPINLOCK(pmu_backlight_lock);21static int sleeping, uses_pmu_bl;22static u8 bl_curve[FB_BACKLIGHT_LEVELS];23 24static void pmu_backlight_init_curve(u8 off, u8 min, u8 max)25{26	int i, flat, count, range = (max - min);27 28	bl_curve[0] = off;29 30	for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)31		bl_curve[flat] = min;32 33	count = FB_BACKLIGHT_LEVELS * 15 / 16;34	for (i = 0; i < count; ++i)35		bl_curve[flat + i] = min + (range * (i + 1) / count);36}37 38static int pmu_backlight_curve_lookup(int value)39{40	int level = (FB_BACKLIGHT_LEVELS - 1);41	int i, max = 0;42 43	/* Look for biggest value */44	for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)45		max = max((int)bl_curve[i], max);46 47	/* Look for nearest value */48	for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {49		int diff = abs(bl_curve[i] - value);50		if (diff < max) {51			max = diff;52			level = i;53		}54	}55	return level;56}57 58static int pmu_backlight_get_level_brightness(int level)59{60	int pmulevel;61 62	/* Get and convert the value */63	pmulevel = bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;64	if (pmulevel < 0)65		pmulevel = 0;66	else if (pmulevel > MAX_PMU_LEVEL)67		pmulevel = MAX_PMU_LEVEL;68 69	return pmulevel;70}71 72static int __pmu_backlight_update_status(struct backlight_device *bd)73{74	struct adb_request req;75	int level = backlight_get_brightness(bd);76 77	if (level > 0) {78		int pmulevel = pmu_backlight_get_level_brightness(level);79 80		pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);81		pmu_wait_complete(&req);82 83		pmu_request(&req, NULL, 2, PMU_POWER_CTRL,84			PMU_POW_BACKLIGHT | PMU_POW_ON);85		pmu_wait_complete(&req);86	} else {87		pmu_request(&req, NULL, 2, PMU_POWER_CTRL,88			PMU_POW_BACKLIGHT | PMU_POW_OFF);89		pmu_wait_complete(&req);90	}91 92	return 0;93}94 95static int pmu_backlight_update_status(struct backlight_device *bd)96{97	unsigned long flags;98	int rc = 0;99 100	spin_lock_irqsave(&pmu_backlight_lock, flags);101	/* Don't update brightness when sleeping */102	if (!sleeping)103		rc = __pmu_backlight_update_status(bd);104	spin_unlock_irqrestore(&pmu_backlight_lock, flags);105	return rc;106}107 108 109static const struct backlight_ops pmu_backlight_data = {110	.update_status	= pmu_backlight_update_status,111 112};113 114#ifdef CONFIG_PM115void pmu_backlight_set_sleep(int sleep)116{117	unsigned long flags;118 119	spin_lock_irqsave(&pmu_backlight_lock, flags);120	sleeping = sleep;121	if (pmac_backlight && uses_pmu_bl) {122		if (sleep) {123			struct adb_request req;124 125			pmu_request(&req, NULL, 2, PMU_POWER_CTRL,126				    PMU_POW_BACKLIGHT | PMU_POW_OFF);127			pmu_wait_complete(&req);128		} else129			__pmu_backlight_update_status(pmac_backlight);130	}131	spin_unlock_irqrestore(&pmu_backlight_lock, flags);132}133#endif /* CONFIG_PM */134 135void __init pmu_backlight_init(void)136{137	struct backlight_properties props;138	struct backlight_device *bd;139	char name[10];140	int level, autosave;141 142	/* Special case for the old PowerBook since I can't test on it */143	autosave =144		of_machine_is_compatible("AAPL,3400/2400") ||145		of_machine_is_compatible("AAPL,3500");146 147	if (!autosave &&148	    !pmac_has_backlight_type("pmu") &&149	    !of_machine_is_compatible("AAPL,PowerBook1998") &&150	    !of_machine_is_compatible("PowerBook1,1"))151		return;152 153	snprintf(name, sizeof(name), "pmubl");154 155	memset(&props, 0, sizeof(struct backlight_properties));156	props.type = BACKLIGHT_PLATFORM;157	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;158	bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data,159				       &props);160	if (IS_ERR(bd)) {161		printk(KERN_ERR "PMU Backlight registration failed\n");162		return;163	}164	uses_pmu_bl = 1;165	pmu_backlight_init_curve(0x7F, 0x46, 0x0E);166 167	level = bd->props.max_brightness;168 169	if (autosave) {170		/* read autosaved value if available */171		struct adb_request req;172		pmu_request(&req, NULL, 2, 0xd9, 0);173		pmu_wait_complete(&req);174 175		level = pmu_backlight_curve_lookup(176				(req.reply[0] >> 4) *177				bd->props.max_brightness / 15);178	}179 180	bd->props.brightness = level;181	bd->props.power = BACKLIGHT_POWER_ON;182	backlight_update_status(bd);183 184	printk(KERN_INFO "PMU Backlight initialized (%s)\n", name);185}186