2 * Dynamic Binary Instrumentation Module based on KProbes
3 * energy/lcd/lcd_base.c
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * Copyright (C) Samsung Electronics, 2013
21 * 2013 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
26 #include <linux/module.h>
27 #include <linux/slab.h>
30 #include <energy/tm_stat.h>
31 #include <energy/debugfs_energy.h>
33 #include "lcd_debugfs.h"
37 * @brief Read the number of file
39 * @param path of the file
40 * @return Value or error(when negative)
42 int read_val(const char *path)
47 enum { buf_len = 32 };
50 f = filp_open(path, O_RDONLY, 0);
52 printk(KERN_INFO "cannot open file \'%s\'", path);
56 ret = kernel_read(f, 0, buf, sizeof(buf));
61 buf[ret >= buf_len ? buf_len - 1 : ret] = '\0';
63 ret = strict_strtoul(buf, 0, &val);
80 struct lcd_priv_data {
85 struct tm_stat *tms_brt;
96 static void *create_lcd_priv(struct lcd_ops *ops, size_t tms_brt_cnt)
99 struct lcd_priv_data *lcd;
101 if (tms_brt_cnt <= 0) {
102 printk(KERN_INFO "error variable tms_brt_cnt=%d\n",
107 lcd = kmalloc(sizeof(*lcd) + sizeof(*lcd->tms_brt) * tms_brt_cnt,
110 printk(KERN_INFO "error: %s - out of memory\n", __func__);
114 lcd->tms_brt = (void *)lcd + sizeof(*lcd);
115 lcd->tms_brt_cnt = tms_brt_cnt;
117 lcd->min_brt = ops->get(ops, LPD_MIN_BRIGHTNESS);
118 lcd->max_brt = ops->get(ops, LPD_MAX_BRIGHTNESS);
120 for (i = 0; i < tms_brt_cnt; ++i)
121 tm_stat_init(&lcd->tms_brt[i]);
123 spin_lock_init(&lcd->lock_tms);
125 lcd->brt_old = brt_no_init;
136 static void destroy_lcd_priv(void *data)
141 static struct lcd_priv_data *get_lcd_priv(struct lcd_ops *ops)
143 return (struct lcd_priv_data *)ops->priv;
146 static void clean_brightness(struct lcd_ops *ops)
148 struct lcd_priv_data *lcd = get_lcd_priv(ops);
151 spin_lock(&lcd->lock_tms);
152 for (i = 0; i < lcd->tms_brt_cnt; ++i)
153 tm_stat_init(&lcd->tms_brt[i]);
155 lcd->brt_old = brt_no_init;
156 spin_unlock(&lcd->lock_tms);
159 static int get_brt_num_of_array(struct lcd_priv_data *lcd, int brt)
161 if (brt > lcd->max_brt || brt < lcd->min_brt) {
162 printk(KERN_INFO "LCD energy error: set brightness=%d, "
163 "when brightness[%d..%d]\n",
164 brt, lcd->min_brt, lcd->max_brt);
165 brt = brt > lcd->max_brt ? lcd->max_brt : lcd->min_brt;
168 return lcd->tms_brt_cnt * (brt - lcd->min_brt) /
169 (lcd->max_brt - lcd->min_brt + 1);
172 static void set_brightness(struct lcd_ops *ops, int brt)
174 struct lcd_priv_data *lcd = get_lcd_priv(ops);
175 int n = get_brt_num_of_array(lcd, brt);
177 spin_lock(&lcd->lock_tms);
179 if (lcd->power == PW_ON && lcd->brt_old != n) {
180 u64 time = get_ntime();
181 if (lcd->brt_old != brt_no_init)
182 tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
184 tm_stat_set_timestamp(&lcd->tms_brt[n], time);
188 spin_unlock(&lcd->lock_tms);
191 static void set_power_on_set_brt(struct lcd_priv_data *lcd)
193 if (lcd->brt_old != brt_no_init) {
194 u64 time = get_ntime();
195 tm_stat_set_timestamp(&lcd->tms_brt[lcd->brt_old], time);
199 static void set_power_on(struct lcd_priv_data *lcd)
201 if (lcd->power == PW_OFF)
202 set_power_on_set_brt(lcd);
207 static void set_power_off_update_brt(struct lcd_priv_data *lcd)
209 if (lcd->brt_old != brt_no_init) {
210 u64 time = get_ntime();
211 tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
212 lcd->brt_old = brt_no_init;
216 static void set_power_off(struct lcd_priv_data *lcd)
218 if (lcd->power == PW_ON)
219 set_power_off_update_brt(lcd);
224 static void set_power(struct lcd_ops *ops, int val)
226 struct lcd_priv_data *lcd = get_lcd_priv(ops);
228 spin_lock(&lcd->lock_tms);
231 case FB_BLANK_UNBLANK:
234 case FB_BLANK_POWERDOWN:
238 printk(KERN_INFO "LCD energy error: set power=%d\n", val);
242 spin_unlock(&lcd->lock_tms);
245 static int func_notifier_lcd(struct lcd_ops *ops, enum lcd_action_type action,
250 set_brightness(ops, (int)data);
253 set_power(ops, (int)data);
256 printk(KERN_INFO "LCD energy error: action=%d\n", action);
264 * @brief Get the array size of LCD
266 * @param ops LCD operations
269 size_t get_lcd_size_array(struct lcd_ops *ops)
271 struct lcd_priv_data *lcd = get_lcd_priv(ops);
273 return lcd->tms_brt_cnt;
277 * @brief Get an array of times
279 * @param ops LCD operations
280 * @param array_time[out] Array of times
283 void get_lcd_array_time(struct lcd_ops *ops, u64 *array_time)
285 struct lcd_priv_data *lcd = get_lcd_priv(ops);
288 spin_lock(&lcd->lock_tms);
289 for (i = 0; i < lcd->tms_brt_cnt; ++i)
290 array_time[i] = tm_stat_running(&lcd->tms_brt[i]);
292 if (lcd->power == PW_ON && lcd->brt_old != brt_no_init) {
293 int old = lcd->brt_old;
294 struct tm_stat *tm = &lcd->tms_brt[old];
296 array_time[old] += get_ntime() - tm_stat_timestamp(tm);
298 spin_unlock(&lcd->lock_tms);
301 static int register_lcd(struct lcd_ops *ops)
305 ops->priv = create_lcd_priv(ops, brt_cnt);
307 /* TODO: create init_func() for 'struct rational' */
308 ops->min_coef.num = 1;
309 ops->min_coef.denom = 1;
310 ops->max_coef.num = 1;
311 ops->max_coef.denom = 1;
313 ops->notifier = func_notifier_lcd;
315 ret = register_lcd_debugfs(ops);
317 destroy_lcd_priv(ops->priv);
322 static void unregister_lcd(struct lcd_ops *ops)
324 unregister_lcd_debugfs(ops);
325 destroy_lcd_priv(ops->priv);
331 /* ============================================================================
332 * === LCD_INIT/LCD_EXIT ===
333 * ============================================================================
335 typedef struct lcd_ops *(*get_ops_t)(void);
339 get_ops_t lcd_ops[] = DEFINITION_LCD_ARRAY;
340 enum { lcd_ops_cnt = sizeof(lcd_ops) / sizeof(get_ops_t) };
343 SLO_REGISTER = 1 << 0,
347 static DEFINE_MUTEX(lcd_lock);
348 static enum ST_LCD_OPS stat_lcd_ops[lcd_ops_cnt];
350 static void do_lcd_exit(void)
355 mutex_lock(&lcd_lock);
356 for (i = 0; i < lcd_ops_cnt; ++i) {
359 if (stat_lcd_ops[i] & SLO_SET) {
361 stat_lcd_ops[i] &= ~SLO_SET;
364 if (stat_lcd_ops[i] & SLO_REGISTER) {
366 stat_lcd_ops[i] &= ~SLO_REGISTER;
369 mutex_unlock(&lcd_lock);
373 * @brief LCD deinitialization
382 static int do_lcd_init(void)
384 int i, ret, count = 0;
387 mutex_lock(&lcd_lock);
388 for (i = 0; i < lcd_ops_cnt; ++i) {
391 printk(KERN_INFO "error %s [ops == NULL]\n", __func__);
395 if (0 == ops->check(ops)) {
396 printk(KERN_INFO "error checking %s\n", ops->name);
400 ret = register_lcd(ops);
402 printk(KERN_INFO "error register_lcd %s\n", ops->name);
406 stat_lcd_ops[i] |= SLO_REGISTER;
409 mutex_unlock(&lcd_lock);
411 return count ? 0 : -EPERM;
415 * @brief LCD initialization
425 printk(KERN_INFO "LCD is not supported\n");
432 /* ============================================================================
433 * === LCD_SET_ENERGY/LCD_UNSET_ENERGY ===
434 * ============================================================================
438 * @brief Start measuring the energy consumption of LСD
442 int lcd_set_energy(void)
444 int i, ret, count = 0;
447 mutex_lock(&lcd_lock);
448 for (i = 0; i < lcd_ops_cnt; ++i) {
450 if (stat_lcd_ops[i] & SLO_REGISTER) {
453 printk(KERN_INFO "error %s set LCD energy",
458 set_brightness(ops, ops->get(ops, LPD_BRIGHTNESS));
459 set_power(ops, ops->get(ops, LPD_POWER));
461 stat_lcd_ops[i] |= SLO_SET;
465 mutex_unlock(&lcd_lock);
467 return count ? 0 : -EPERM;
471 * @brief Stop measuring the energy consumption of LСD
475 void lcd_unset_energy(void)
480 mutex_lock(&lcd_lock);
481 for (i = 0; i < lcd_ops_cnt; ++i) {
483 if (stat_lcd_ops[i] & SLO_SET) {
484 ret = ops->unset(ops);
486 printk(KERN_INFO "error %s unset LCD energy",
489 clean_brightness(ops);
490 stat_lcd_ops[i] &= ~SLO_SET;
493 mutex_unlock(&lcd_lock);