aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/samsung/lcdfreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/samsung/lcdfreq.c')
-rw-r--r--drivers/video/samsung/lcdfreq.c105
1 files changed, 85 insertions, 20 deletions
diff --git a/drivers/video/samsung/lcdfreq.c b/drivers/video/samsung/lcdfreq.c
index 8c25c22..7e4af07 100644
--- a/drivers/video/samsung/lcdfreq.c
+++ b/drivers/video/samsung/lcdfreq.c
@@ -21,8 +21,6 @@
#include "s3cfb.h"
-#define LCDFREQ_LIMIT_HZ 40
-
enum lcdfreq_level_idx {
LEVEL_NORMAL,
LEVEL_LIMIT,
@@ -217,30 +215,44 @@ int get_divider(struct fb_info *fb)
fimd_div = gcd(lcdfreq->table[LEVEL_NORMAL].cmu_clkdiv, lcdfreq->table[LEVEL_LIMIT].cmu_clkdiv);
+ if ((!fimd_div) || (fimd_div > 16)) {
+ dev_info(fb->dev, "%s skip, %d\n", __func__, __LINE__);
+ goto err;
+ }
+
lcdfreq->table[LEVEL_NORMAL].cmu_clkdiv /= fimd_div;
lcdfreq->table[LEVEL_LIMIT].cmu_clkdiv /= fimd_div;
dev_info(fb->dev, "%s rate is %d, fimd divider=%d\n", clk->name, rate, fimd_div);
+ fimd_div--;
for (i = 0; i < LCDFREQ_LEVEL_END; i++) {
- lcdfreq->table[i].cmu_clkdiv--;
- dev_info(fb->dev, "%dHZ divider is %d\n",
+ if (lcdfreq->table[i].cmu_clkdiv > 16) {
+ dev_info(fb->dev, "%s skip, %d\n", __func__, __LINE__);
+ goto err;
+ }
+ dev_info(fb->dev, "%dhz div is %d\n",
lcdfreq->table[i].hz, lcdfreq->table[i].cmu_clkdiv);
+ lcdfreq->table[i].cmu_clkdiv--;
}
reg = (readl(fbdev->regs + S3C_VIDCON0) & (S3C_VIDCON0_CLKVAL_F(0xff))) >> 6;
- reg++;
-
- if (fimd_div != reg)
- return -EINVAL;
+ if (fimd_div != reg) {
+ dev_info(fb->dev, "%s skip, %d\n", __func__, __LINE__);
+ goto err;
+ }
reg = (readl(sclk->reg_div.reg)) >> sclk->reg_div.shift;
reg &= 0xf;
-
- if (lcdfreq->table[LEVEL_NORMAL].cmu_clkdiv != reg)
- return -EINVAL;
+ if (lcdfreq->table[LEVEL_NORMAL].cmu_clkdiv != reg) {
+ dev_info(fb->dev, "%s skip, %d\n", __func__, __LINE__);
+ goto err;
+ }
return 0;
+
+err:
+ return -EINVAL;
}
static ssize_t level_show(struct device *dev,
@@ -256,7 +268,7 @@ static ssize_t level_show(struct device *dev,
return -EINVAL;
}
- return sprintf(buf, "%dHZ, div=%d\n", lcdfreq->table[lcdfreq->level].hz, get_div(fbdev));
+ return sprintf(buf, "%dhz, div=%d\n", lcdfreq->table[lcdfreq->level].hz, get_div(fbdev));
}
static ssize_t level_store(struct device *dev,
@@ -296,12 +308,61 @@ static ssize_t usage_show(struct device *dev,
return sprintf(buf, "%d\n", atomic_read(&lcdfreq->usage));
}
+#if 0
+static ssize_t freq_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fb = dev_get_drvdata(dev);
+ struct s3cfb_window *win = fb->par;
+ struct s3cfb_global *fbdev = get_fimd_global(win->id);
+ struct s3cfb_lcd *lcd = fbdev->lcd;
+
+ return sprintf(buf, "%dhz, hfp=%d, hbp=%d, hsw=%d, div=%d\n", lcd->freq,
+ lcd->timing.h_fp, lcd->timing.h_bp, lcd->timing.h_sw, get_div(fbdev)+1);
+}
+
+extern void s5p_dsim_set_lcd_freq_change(struct s3cfb_lcd_timing *timing);
+
+static ssize_t freq_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct fb_info *fb = dev_get_drvdata(dev);
+ struct s3cfb_window *win = fb->par;
+ struct s3cfb_global *fbdev = get_fimd_global(win->id);
+ struct s3cfb_lcd *lcd = fbdev->lcd;
+ struct s3cfb_lcd_timing *timing = &lcd->timing;
+ struct fb_var_screeninfo *var = &fb->var;
+
+ lcd->freq_limit = 0;
+ sscanf(buf, "%d %d %d %d", &lcd->freq,
+ &timing->h_fp, &timing->h_bp, &timing->h_sw);
+
+ var->hsync_len = timing->h_sw;
+ var->left_margin = timing->h_bp;
+ var->right_margin = timing->h_fp;
+
+ var->pixclock = (lcd->freq *
+ (var->left_margin + var->right_margin
+ + var->hsync_len + var->xres) *
+ (var->upper_margin + var->lower_margin
+ + var->vsync_len + var->yres));
+ var->pixclock = KHZ2PICOS(var->pixclock/1000);
+
+ s5p_dsim_set_lcd_freq_change(timing);
+
+ return count;
+}
+
+static DEVICE_ATTR(freq, S_IRUGO|S_IWUSR, freq_show, freq_store);
+#endif
+
static DEVICE_ATTR(level, S_IRUGO|S_IWUSR, level_show, level_store);
static DEVICE_ATTR(usage, S_IRUGO, usage_show, NULL);
static struct attribute *lcdfreq_attributes[] = {
&dev_attr_level.attr,
&dev_attr_usage.attr,
+/* &dev_attr_freq.attr, */
NULL,
};
@@ -323,7 +384,7 @@ static void lcdfreq_early_suspend(struct early_suspend *h)
atomic_set(&lcdfreq->usage, 0);
mutex_unlock(&lcdfreq->lock);
- return ;
+ return;
}
static void lcdfreq_late_resume(struct early_suspend *h)
@@ -392,7 +453,7 @@ static void lcdfreq_status_work(struct work_struct *work)
cancel_delayed_work(&lcdfreq->work);
- dev_info(lcdfreq->dev, "\tHZ=%d, usage=%d\n", hz, atomic_read(&lcdfreq->usage));
+ dev_info(lcdfreq->dev, "\thz=%d, usage=%d\n", hz, atomic_read(&lcdfreq->usage));
schedule_delayed_work(&lcdfreq->work, HZ*120);
}
@@ -405,8 +466,8 @@ int lcdfreq_init(struct fb_info *fb)
struct fb_var_screeninfo *var = &fb->var;
struct lcdfreq_info *lcdfreq = NULL;
- u32 vclk = 0;
- int ret;
+ u32 vclk;
+ int ret = 0;
lcdfreq = kzalloc(sizeof(struct lcdfreq_info), GFP_KERNEL);
if (!lcdfreq) {
@@ -415,6 +476,11 @@ int lcdfreq_init(struct fb_info *fb)
goto err_1;
}
+ if (!lcd->freq_limit) {
+ ret = -EINVAL;
+ goto err_2;
+ }
+
fbdev->data = lcdfreq;
lcdfreq->dev = fb->dev;
@@ -430,7 +496,7 @@ int lcdfreq_init(struct fb_info *fb)
lcdfreq->table[LEVEL_NORMAL].pixclock = var->pixclock;
lcdfreq->table[LEVEL_NORMAL].hz = lcd->freq;
- vclk = (LCDFREQ_LIMIT_HZ *
+ vclk = (lcd->freq_limit *
(var->left_margin + var->right_margin
+ var->hsync_len + var->xres) *
(var->upper_margin + var->lower_margin
@@ -438,11 +504,11 @@ int lcdfreq_init(struct fb_info *fb)
lcdfreq->table[LEVEL_LIMIT].level = LEVEL_LIMIT;
lcdfreq->table[LEVEL_LIMIT].vclk = vclk;
lcdfreq->table[LEVEL_LIMIT].pixclock = KHZ2PICOS(vclk/1000);
- lcdfreq->table[LEVEL_LIMIT].hz = LCDFREQ_LIMIT_HZ;
+ lcdfreq->table[LEVEL_LIMIT].hz = lcd->freq_limit;
ret = get_divider(fb);
if (ret < 0) {
- pr_err("fail to init lcd freq switch");
+ pr_err("skip lcd freq switch init");
fbdev->data = NULL;
goto err_1;
}
@@ -489,4 +555,3 @@ err_1:
return ret;
}
-