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