1891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto/* 2891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * LED Heartbeat Trigger 3891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * 4891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> 5891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * 6891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * Based on Richard Purdie's ledtrig-timer.c and some arch's 7891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * CONFIG_HEARTBEAT code. 8891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * 9891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * This program is free software; you can redistribute it and/or modify 10891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * it under the terms of the GNU General Public License version 2 as 11891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * published by the Free Software Foundation. 12891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * 13891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto */ 14891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto#include <linux/module.h> 15891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto#include <linux/kernel.h> 16891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto#include <linux/init.h> 175a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 18891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto#include <linux/timer.h> 19891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto#include <linux/sched.h> 20891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto#include <linux/leds.h> 21891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto#include "leds.h" 22891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 23891c668b90ded38cec36f0852c4983573597170dAtsushi Nemotostruct heartbeat_trig_data { 24891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto unsigned int phase; 25891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto unsigned int period; 26891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto struct timer_list timer; 27891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto}; 28891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 29891c668b90ded38cec36f0852c4983573597170dAtsushi Nemotostatic void led_heartbeat_function(unsigned long data) 30891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto{ 31891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto struct led_classdev *led_cdev = (struct led_classdev *) data; 32891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data; 33891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto unsigned long brightness = LED_OFF; 34891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto unsigned long delay = 0; 35891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 36891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto /* acts like an actual heart beat -- ie thump-thump-pause... */ 37891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto switch (heartbeat_data->phase) { 38891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto case 0: 39891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto /* 40891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * The hyperbolic function below modifies the 41891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * heartbeat period length in dependency of the 42891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * current (1min) load. It goes through the points 43891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto * f(0)=1260, f(1)=860, f(5)=510, f(inf)->300. 44891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto */ 45891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto heartbeat_data->period = 300 + 46891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto (6720 << FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT)); 47891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto heartbeat_data->period = 48891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto msecs_to_jiffies(heartbeat_data->period); 49891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto delay = msecs_to_jiffies(70); 50891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto heartbeat_data->phase++; 511bd465e6b0e2b559db47420fea686507a01cfab0Guennadi Liakhovetski brightness = led_cdev->max_brightness; 52891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto break; 53891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto case 1: 54891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto delay = heartbeat_data->period / 4 - msecs_to_jiffies(70); 55891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto heartbeat_data->phase++; 56891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto break; 57891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto case 2: 58891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto delay = msecs_to_jiffies(70); 59891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto heartbeat_data->phase++; 601bd465e6b0e2b559db47420fea686507a01cfab0Guennadi Liakhovetski brightness = led_cdev->max_brightness; 61891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto break; 62891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto default: 63891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto delay = heartbeat_data->period - heartbeat_data->period / 4 - 64891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto msecs_to_jiffies(70); 65891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto heartbeat_data->phase = 0; 66891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto break; 67891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto } 68891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 69891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto led_set_brightness(led_cdev, brightness); 70891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto mod_timer(&heartbeat_data->timer, jiffies + delay); 71891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto} 72891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 73891c668b90ded38cec36f0852c4983573597170dAtsushi Nemotostatic void heartbeat_trig_activate(struct led_classdev *led_cdev) 74891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto{ 75891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto struct heartbeat_trig_data *heartbeat_data; 76891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 77891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto heartbeat_data = kzalloc(sizeof(*heartbeat_data), GFP_KERNEL); 78891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto if (!heartbeat_data) 79891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto return; 80891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 81891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto led_cdev->trigger_data = heartbeat_data; 82891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto setup_timer(&heartbeat_data->timer, 83891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto led_heartbeat_function, (unsigned long) led_cdev); 84891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto heartbeat_data->phase = 0; 85891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto led_heartbeat_function(heartbeat_data->timer.data); 86891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto} 87891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 88891c668b90ded38cec36f0852c4983573597170dAtsushi Nemotostatic void heartbeat_trig_deactivate(struct led_classdev *led_cdev) 89891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto{ 90891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data; 91891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 92891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto if (heartbeat_data) { 93891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto del_timer_sync(&heartbeat_data->timer); 94891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto kfree(heartbeat_data); 95891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto } 96891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto} 97891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 98891c668b90ded38cec36f0852c4983573597170dAtsushi Nemotostatic struct led_trigger heartbeat_led_trigger = { 99891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto .name = "heartbeat", 100891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto .activate = heartbeat_trig_activate, 101891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto .deactivate = heartbeat_trig_deactivate, 102891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto}; 103891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 104891c668b90ded38cec36f0852c4983573597170dAtsushi Nemotostatic int __init heartbeat_trig_init(void) 105891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto{ 106891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto return led_trigger_register(&heartbeat_led_trigger); 107891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto} 108891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 109891c668b90ded38cec36f0852c4983573597170dAtsushi Nemotostatic void __exit heartbeat_trig_exit(void) 110891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto{ 111891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto led_trigger_unregister(&heartbeat_led_trigger); 112891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto} 113891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 114891c668b90ded38cec36f0852c4983573597170dAtsushi Nemotomodule_init(heartbeat_trig_init); 115891c668b90ded38cec36f0852c4983573597170dAtsushi Nemotomodule_exit(heartbeat_trig_exit); 116891c668b90ded38cec36f0852c4983573597170dAtsushi Nemoto 117891c668b90ded38cec36f0852c4983573597170dAtsushi NemotoMODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>"); 118891c668b90ded38cec36f0852c4983573597170dAtsushi NemotoMODULE_DESCRIPTION("Heartbeat LED trigger"); 119891c668b90ded38cec36f0852c4983573597170dAtsushi NemotoMODULE_LICENSE("GPL"); 120