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>
29 #include <energy/tm_stat.h>
31 #include "lcd_debugfs.h"
34 int read_val(const char *path)
39 enum { buf_len = 32 };
42 f = filp_open(path, O_RDONLY, 0);
44 printk("cannot open file \'%s\'", path);
48 ret = kernel_read(f, 0, buf, sizeof(buf));
53 buf[ret >= buf_len ? buf_len - 1 : ret] = '\0';
55 ret = strict_strtoul(buf, 0, &val);
67 struct lcd_priv_data {
72 struct tm_stat *tms_brt;
82 static void *create_lcd_priv(struct lcd_ops *ops, size_t tms_brt_cnt)
85 struct lcd_priv_data *lcd;
87 if (tms_brt_cnt <= 0) {
88 printk("error variable tms_brt_cnt=%d\n", tms_brt_cnt);
92 lcd = kmalloc(sizeof(*lcd) + sizeof(*lcd->tms_brt) * tms_brt_cnt,
95 printk("error: %s - out of memory\n", __func__);
99 lcd->tms_brt = (void *)lcd + sizeof(*lcd);
100 lcd->tms_brt_cnt = tms_brt_cnt;
102 lcd->min_brt = ops->get(ops, LPD_MIN_BRIGHTNESS);
103 lcd->max_brt = ops->get(ops, LPD_MAX_BRIGHTNESS);
105 for (i = 0; i < tms_brt_cnt; ++i)
106 tm_stat_init(&lcd->tms_brt[i]);
108 spin_lock_init(&lcd->lock_tms);
110 lcd->brt_old = brt_no_init;
120 static void destroy_lcd_priv(void *data)
125 static struct lcd_priv_data *get_lcd_priv(struct lcd_ops *ops)
127 return (struct lcd_priv_data *)ops->priv;
130 static void clean_brightness(struct lcd_ops *ops)
132 struct lcd_priv_data *lcd = get_lcd_priv(ops);
135 spin_lock(&lcd->lock_tms);
136 for (i = 0; i < lcd->tms_brt_cnt; ++i)
137 tm_stat_init(&lcd->tms_brt[i]);
139 lcd->brt_old = brt_no_init;
140 spin_unlock(&lcd->lock_tms);
143 static void set_brightness(struct lcd_ops *ops, int brt)
145 struct lcd_priv_data *lcd = get_lcd_priv(ops);
148 if (brt > lcd->max_brt || brt < lcd->min_brt) {
149 printk("LCD energy error: set brightness=%d, "
150 "when brightness[%d..%d]\n",
151 brt, lcd->min_brt, lcd->max_brt);
152 brt = brt > lcd->max_brt ? lcd->max_brt : lcd->min_brt;
155 n = lcd->tms_brt_cnt * (brt - lcd->min_brt) /
156 (lcd->max_brt - lcd->min_brt + 1);
158 spin_lock(&lcd->lock_tms);
159 if (lcd->brt_old != n) {
160 u64 time = get_ntime();
161 if (lcd->brt_old != brt_no_init)
162 tm_stat_update(&lcd->tms_brt[lcd->brt_old], time);
164 tm_stat_set_timestamp(&lcd->tms_brt[n], time);
167 spin_unlock(&lcd->lock_tms);
170 static int func_notifier_lcd(struct lcd_ops *ops, enum lcd_action_type action,
175 set_brightness(ops, (int)data);
184 size_t get_lcd_size_array(struct lcd_ops *ops)
186 struct lcd_priv_data *lcd = get_lcd_priv(ops);
188 return lcd->tms_brt_cnt;
191 void get_lcd_array_time(struct lcd_ops *ops, u64 *array_time)
193 struct lcd_priv_data *lcd = get_lcd_priv(ops);
196 spin_lock(&lcd->lock_tms);
197 for (i = 0; i < lcd->tms_brt_cnt; ++i) {
198 array_time[i] = tm_stat_running(&lcd->tms_brt[i]);
199 if (i == lcd->brt_old)
200 array_time[i] += get_ntime() -
201 tm_stat_timestamp(&lcd->tms_brt[i]);
203 spin_unlock(&lcd->lock_tms);
206 static int register_lcd(struct lcd_ops *ops)
210 ops->priv = create_lcd_priv(ops, brt_cnt);
212 /* TODO: create init_func() for 'struct rational' */
213 ops->min_coef.num = 1;
214 ops->min_coef.denom = 1;
215 ops->max_coef.num = 1;
216 ops->max_coef.denom = 1;
218 ops->notifier = func_notifier_lcd;
220 ret = register_lcd_debugfs(ops);
222 destroy_lcd_priv(ops->priv);
227 static void unregister_lcd(struct lcd_ops *ops)
229 unregister_lcd_debugfs(ops);
230 destroy_lcd_priv(ops->priv);
236 /* ============================================================================
237 * === LCD_INIT/LCD_EXIT ===
238 * ============================================================================
240 typedef struct lcd_ops *(*get_ops_t)(void);
244 get_ops_t lcd_ops[] = DEFINITION_LCD_ARRAY;
245 enum { lcd_ops_cnt = sizeof(lcd_ops) / sizeof(get_ops_t) };
248 SLO_REGISTER = 1 << 0,
252 static DEFINE_MUTEX(lcd_lock);
253 static enum ST_LCD_OPS stat_lcd_ops[lcd_ops_cnt];
260 mutex_lock(&lcd_lock);
261 for (i = 0; i < lcd_ops_cnt; ++i) {
264 if (stat_lcd_ops[i] & SLO_SET) {
266 stat_lcd_ops[i] &= ~SLO_SET;
269 if (stat_lcd_ops[i] & SLO_REGISTER) {
271 stat_lcd_ops[i] &= ~SLO_REGISTER;
274 mutex_unlock(&lcd_lock);
279 int i, ret, count = 0;
282 mutex_lock(&lcd_lock);
283 for (i = 0; i < lcd_ops_cnt; ++i) {
286 printk("error %s [ops == NULL]\n", __func__);
290 if (0 == ops->check(ops)) {
291 printk("error checking %s\n", ops->name);
295 ret = register_lcd(ops);
297 printk("error register_lcd %s\n", ops->name);
301 stat_lcd_ops[i] |= SLO_REGISTER;
304 mutex_unlock(&lcd_lock);
306 return count ? 0 : -EPERM;
313 /* ============================================================================
314 * === LCD_SET_ENERGY/LCD_UNSET_ENERGY ===
315 * ============================================================================
317 int lcd_set_energy(void)
319 int i, ret, count = 0;
322 mutex_lock(&lcd_lock);
323 for (i = 0; i < lcd_ops_cnt; ++i) {
325 if (stat_lcd_ops[i] & SLO_REGISTER) {
328 printk("error %s set LCD energy", ops->name);
332 set_brightness(ops, ops->get(ops, LPD_BRIGHTNESS));
334 stat_lcd_ops[i] |= SLO_SET;
338 mutex_unlock(&lcd_lock);
340 return count ? 0 : -EPERM;
343 void lcd_unset_energy(void)
348 mutex_lock(&lcd_lock);
349 for (i = 0; i < lcd_ops_cnt; ++i) {
351 if (stat_lcd_ops[i] & SLO_SET) {
352 ret = ops->unset(ops);
354 printk("error %s unset LCD energy", ops->name);
356 clean_brightness(ops);
357 stat_lcd_ops[i] &= ~SLO_SET;
360 mutex_unlock(&lcd_lock);