xref: /OK3568_Linux_fs/kernel/drivers/macintosh/via-pmu-led.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * via-pmu LED class device
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
7*4882a593Smuzhiyun  * it under the terms of the GNU General Public License as published by
8*4882a593Smuzhiyun  * the Free Software Foundation; either version 2 of the License, or
9*4882a593Smuzhiyun  * (at your option) any later version.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful, but
12*4882a593Smuzhiyun  * WITHOUT ANY WARRANTY; without even the implied warranty of
13*4882a593Smuzhiyun  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14*4882a593Smuzhiyun  * NON INFRINGEMENT.  See the GNU General Public License for more
15*4882a593Smuzhiyun  * details.
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * You should have received a copy of the GNU General Public License
18*4882a593Smuzhiyun  * along with this program; if not, write to the Free Software
19*4882a593Smuzhiyun  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  */
22*4882a593Smuzhiyun #include <linux/types.h>
23*4882a593Smuzhiyun #include <linux/kernel.h>
24*4882a593Smuzhiyun #include <linux/device.h>
25*4882a593Smuzhiyun #include <linux/leds.h>
26*4882a593Smuzhiyun #include <linux/adb.h>
27*4882a593Smuzhiyun #include <linux/pmu.h>
28*4882a593Smuzhiyun #include <asm/prom.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static spinlock_t pmu_blink_lock;
31*4882a593Smuzhiyun static struct adb_request pmu_blink_req;
32*4882a593Smuzhiyun /* -1: no change, 0: request off, 1: request on */
33*4882a593Smuzhiyun static int requested_change;
34*4882a593Smuzhiyun 
pmu_req_done(struct adb_request * req)35*4882a593Smuzhiyun static void pmu_req_done(struct adb_request * req)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	unsigned long flags;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	spin_lock_irqsave(&pmu_blink_lock, flags);
40*4882a593Smuzhiyun 	/* if someone requested a change in the meantime
41*4882a593Smuzhiyun 	 * (we only see the last one which is fine)
42*4882a593Smuzhiyun 	 * then apply it now */
43*4882a593Smuzhiyun 	if (requested_change != -1 && !pmu_sys_suspended)
44*4882a593Smuzhiyun 		pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
45*4882a593Smuzhiyun 	/* reset requested change */
46*4882a593Smuzhiyun 	requested_change = -1;
47*4882a593Smuzhiyun 	spin_unlock_irqrestore(&pmu_blink_lock, flags);
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
pmu_led_set(struct led_classdev * led_cdev,enum led_brightness brightness)50*4882a593Smuzhiyun static void pmu_led_set(struct led_classdev *led_cdev,
51*4882a593Smuzhiyun 			enum led_brightness brightness)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	unsigned long flags;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	spin_lock_irqsave(&pmu_blink_lock, flags);
56*4882a593Smuzhiyun 	switch (brightness) {
57*4882a593Smuzhiyun 	case LED_OFF:
58*4882a593Smuzhiyun 		requested_change = 0;
59*4882a593Smuzhiyun 		break;
60*4882a593Smuzhiyun 	case LED_FULL:
61*4882a593Smuzhiyun 		requested_change = 1;
62*4882a593Smuzhiyun 		break;
63*4882a593Smuzhiyun 	default:
64*4882a593Smuzhiyun 		goto out;
65*4882a593Smuzhiyun 		break;
66*4882a593Smuzhiyun 	}
67*4882a593Smuzhiyun 	/* if request isn't done, then don't do anything */
68*4882a593Smuzhiyun 	if (pmu_blink_req.complete && !pmu_sys_suspended)
69*4882a593Smuzhiyun 		pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
70*4882a593Smuzhiyun  out:
71*4882a593Smuzhiyun  	spin_unlock_irqrestore(&pmu_blink_lock, flags);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun static struct led_classdev pmu_led = {
75*4882a593Smuzhiyun 	.name = "pmu-led::front",
76*4882a593Smuzhiyun #ifdef CONFIG_ADB_PMU_LED_DISK
77*4882a593Smuzhiyun 	.default_trigger = "disk-activity",
78*4882a593Smuzhiyun #endif
79*4882a593Smuzhiyun 	.brightness_set = pmu_led_set,
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun 
via_pmu_led_init(void)82*4882a593Smuzhiyun static int __init via_pmu_led_init(void)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	struct device_node *dt;
85*4882a593Smuzhiyun 	const char *model;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	/* only do this on keylargo based models */
88*4882a593Smuzhiyun 	if (pmu_get_model() != PMU_KEYLARGO_BASED)
89*4882a593Smuzhiyun 		return -ENODEV;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	dt = of_find_node_by_path("/");
92*4882a593Smuzhiyun 	if (dt == NULL)
93*4882a593Smuzhiyun 		return -ENODEV;
94*4882a593Smuzhiyun 	model = of_get_property(dt, "model", NULL);
95*4882a593Smuzhiyun 	if (model == NULL) {
96*4882a593Smuzhiyun 		of_node_put(dt);
97*4882a593Smuzhiyun 		return -ENODEV;
98*4882a593Smuzhiyun 	}
99*4882a593Smuzhiyun 	if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
100*4882a593Smuzhiyun 	    strncmp(model, "iBook", strlen("iBook")) != 0 &&
101*4882a593Smuzhiyun 	    strcmp(model, "PowerMac7,2") != 0 &&
102*4882a593Smuzhiyun 	    strcmp(model, "PowerMac7,3") != 0) {
103*4882a593Smuzhiyun 		of_node_put(dt);
104*4882a593Smuzhiyun 		/* ignore */
105*4882a593Smuzhiyun 		return -ENODEV;
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 	of_node_put(dt);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	spin_lock_init(&pmu_blink_lock);
110*4882a593Smuzhiyun 	/* no outstanding req */
111*4882a593Smuzhiyun 	pmu_blink_req.complete = 1;
112*4882a593Smuzhiyun 	pmu_blink_req.done = pmu_req_done;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	return led_classdev_register(NULL, &pmu_led);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun late_initcall(via_pmu_led_init);
118