OMAPDSS: DSI: add new clock calculation code
authorTomi Valkeinen <tomi.valkeinen@ti.com>
Tue, 5 Mar 2013 14:39:00 +0000 (16:39 +0200)
committerTomi Valkeinen <tomi.valkeinen@ti.com>
Wed, 3 Apr 2013 12:19:18 +0000 (15:19 +0300)
Add new way to iterate over DSI PLL and HSDIV clock divisors.
dsi_pll_calc() and dss_hsdiv_calc() provide a generic way to go over
all the divisors, within given clock range. The functions will call a
callback function for each divider set, making the function reusable for
all use cases.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.h

index 110a505..a4e0560 100644 (file)
@@ -1280,6 +1280,75 @@ static int dsi_pll_power(struct platform_device *dsidev,
        return 0;
 }
 
+unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       return clk_get_rate(dsi->sys_clk);
+}
+
+bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
+               unsigned long out_min, dsi_hsdiv_calc_func func, void *data)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int regm, regm_start, regm_stop;
+       unsigned long out_max;
+       unsigned long out;
+
+       out_min = out_min ? out_min : 1;
+       out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+       regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul);
+       regm_stop = min(pll / out_min, dsi->regm_dispc_max);
+
+       for (regm = regm_start; regm <= regm_stop; ++regm) {
+               out = pll / regm;
+
+               if (func(regm, out, data))
+                       return true;
+       }
+
+       return false;
+}
+
+bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
+               unsigned long pll_min, unsigned long pll_max,
+               dsi_pll_calc_func func, void *data)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int regn, regn_start, regn_stop;
+       int regm, regm_start, regm_stop;
+       unsigned long fint, pll;
+       const unsigned long pll_hw_max = 1800000000;
+       unsigned long fint_hw_min, fint_hw_max;
+
+       fint_hw_min = dsi->fint_min;
+       fint_hw_max = dsi->fint_max;
+
+       regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
+       regn_stop = min(clkin / fint_hw_min, dsi->regn_max);
+
+       pll_max = pll_max ? pll_max : ULONG_MAX;
+
+       for (regn = regn_start; regn <= regn_stop; ++regn) {
+               fint = clkin / regn;
+
+               regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
+                               1ul);
+               regm_stop = min3(pll_max / fint / 2,
+                               pll_hw_max / fint / 2,
+                               dsi->regm_max);
+
+               for (regm = regm_start; regm <= regm_stop; ++regm) {
+                       pll = 2 * regm * fint;
+
+                       if (func(regn, regm, fint, pll, data))
+                               return true;
+               }
+       }
+
+       return false;
+}
+
 /* calculate clock rates using dividers in cinfo */
 static int dsi_calc_clock_rates(struct platform_device *dsidev,
                struct dsi_clock_info *cinfo)
index 4180302..dde6cc1 100644 (file)
@@ -295,6 +295,18 @@ void dsi_dump_clocks(struct seq_file *s);
 void dsi_irq_handler(void);
 u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
 
+unsigned long dsi_get_pll_clkin(struct platform_device *dsidev);
+
+typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
+               unsigned long pll, void *data);
+typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc,
+               void *data);
+bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
+               unsigned long out_min, dsi_hsdiv_calc_func func, void *data);
+bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
+               unsigned long pll_min, unsigned long pll_max,
+               dsi_pll_calc_func func, void *data);
+
 unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
 int dsi_pll_set_clock_div(struct platform_device *dsidev,
                struct dsi_clock_info *cinfo);