170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg/* 270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * via-pmu LED class device 370c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * 470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 570c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * 670c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * This program is free software; you can redistribute it and/or modify 770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * it under the terms of the GNU General Public License as published by 870c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * the Free Software Foundation; either version 2 of the License, or 970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * (at your option) any later version. 1070c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * 1170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * This program is distributed in the hope that it will be useful, but 1270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * WITHOUT ANY WARRANTY; without even the implied warranty of 1370c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 1470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * NON INFRINGEMENT. See the GNU General Public License for more 1570c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * details. 1670c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * 1770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * You should have received a copy of the GNU General Public License 1870c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * along with this program; if not, write to the Free Software 1970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 2070c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * 2170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg */ 2270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg#include <linux/types.h> 2370c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg#include <linux/kernel.h> 2470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg#include <linux/device.h> 2570c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg#include <linux/leds.h> 2670c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg#include <linux/adb.h> 2770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg#include <linux/pmu.h> 2870c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg#include <asm/prom.h> 2970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 3070c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Bergstatic spinlock_t pmu_blink_lock; 3170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Bergstatic struct adb_request pmu_blink_req; 3270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg/* -1: no change, 0: request off, 1: request on */ 3370c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Bergstatic int requested_change; 3470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 3570c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Bergstatic void pmu_req_done(struct adb_request * req) 3670c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg{ 3770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg unsigned long flags; 3870c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 3970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg spin_lock_irqsave(&pmu_blink_lock, flags); 4070c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg /* if someone requested a change in the meantime 4170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * (we only see the last one which is fine) 4270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg * then apply it now */ 43f596575e81999c0faf01a2fd340bc96dda058f80Johannes Berg if (requested_change != -1 && !pmu_sys_suspended) 4470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change); 4570c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg /* reset requested change */ 4670c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg requested_change = -1; 4770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg spin_unlock_irqrestore(&pmu_blink_lock, flags); 4870c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg} 4970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 5070c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Bergstatic void pmu_led_set(struct led_classdev *led_cdev, 5170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg enum led_brightness brightness) 5270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg{ 5370c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg unsigned long flags; 5470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 5570c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg spin_lock_irqsave(&pmu_blink_lock, flags); 5670c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg switch (brightness) { 5770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg case LED_OFF: 5870c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg requested_change = 0; 5970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg break; 6070c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg case LED_FULL: 6170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg requested_change = 1; 6270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg break; 6370c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg default: 6470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg goto out; 6570c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg break; 6670c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg } 6770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg /* if request isn't done, then don't do anything */ 68f596575e81999c0faf01a2fd340bc96dda058f80Johannes Berg if (pmu_blink_req.complete && !pmu_sys_suspended) 6970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change); 7070c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg out: 7170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg spin_unlock_irqrestore(&pmu_blink_lock, flags); 7270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg} 7370c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 7470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Bergstatic struct led_classdev pmu_led = { 75db3f520738a8c5bf593e13d4ac71f8da9ffcb964Olaf Hering .name = "pmu-led::front", 763a09aa4730f021ad917a66a0c6d2ff6d616a7e4fJohannes Berg#ifdef CONFIG_ADB_PMU_LED_IDE 7770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg .default_trigger = "ide-disk", 7870c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg#endif 7970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg .brightness_set = pmu_led_set, 8070c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg}; 8170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 8270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Bergstatic int __init via_pmu_led_init(void) 8370c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg{ 8470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg struct device_node *dt; 8570c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg const char *model; 8670c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 8770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg /* only do this on keylargo based models */ 8870c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg if (pmu_get_model() != PMU_KEYLARGO_BASED) 8970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg return -ENODEV; 9070c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 9170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg dt = of_find_node_by_path("/"); 9270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg if (dt == NULL) 9370c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg return -ENODEV; 9401b2726dd11ef198ac6cf8f88974b4427d40ffdbStephen Rothwell model = of_get_property(dt, "model", NULL); 951f7aac6eb585f92756603341cb1d770c797c4867Julia Lawall if (model == NULL) { 961f7aac6eb585f92756603341cb1d770c797c4867Julia Lawall of_node_put(dt); 9770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg return -ENODEV; 981f7aac6eb585f92756603341cb1d770c797c4867Julia Lawall } 9970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 && 100e51b85dcf56c87772b47a0781e6cfa88848b50b8Tony Vroon strncmp(model, "iBook", strlen("iBook")) != 0 && 101e51b85dcf56c87772b47a0781e6cfa88848b50b8Tony Vroon strcmp(model, "PowerMac7,2") != 0 && 102e51b85dcf56c87772b47a0781e6cfa88848b50b8Tony Vroon strcmp(model, "PowerMac7,3") != 0) { 10370c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg of_node_put(dt); 10470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg /* ignore */ 10570c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg return -ENODEV; 10670c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg } 10770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg of_node_put(dt); 10870c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 10970c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg spin_lock_init(&pmu_blink_lock); 11070c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg /* no outstanding req */ 11170c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg pmu_blink_req.complete = 1; 11270c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg pmu_blink_req.done = pmu_req_done; 113f596575e81999c0faf01a2fd340bc96dda058f80Johannes Berg 11470c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg return led_classdev_register(NULL, &pmu_led); 11570c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg} 11670c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berg 11770c3967d4f8029f3d53323a9f0490df61d8cb77dJohannes Berglate_initcall(via_pmu_led_init); 118