File Index
Files and directories
Sign in
FILE

via-pmu-backlight.c

File preview with syntax highlighting.

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