static int tegra_camera_clk_set_rate(struct tegra_camera_dev *dev)
{
- u32 offset;
- struct clk *clk;
+ struct clk *clk, *clk_parent;
struct tegra_camera_clk_info *info = &dev->info;
+ unsigned long parent_rate, parent_div_rate, parent_div_rate_pre;
if (!info) {
dev_err(dev->dev,
switch (info->clk_id) {
case TEGRA_CAMERA_VI_CLK:
clk = dev->vi_clk;
- offset = 0x148;
break;
case TEGRA_CAMERA_VI_SENSOR_CLK:
clk = dev->vi_sensor_clk;
- offset = 0x1a8;
break;
default:
dev_err(dev->dev,
return -EINVAL;
}
- clk_set_rate(clk, info->rate);
-
- if (info->clk_id == TEGRA_CAMERA_VI_CLK) {
- u32 val = 0x2;
- void __iomem *car = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
- void __iomem *apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+ clk_parent = clk_get_parent(clk);
+ parent_rate = clk_get_rate(clk_parent);
+ dev_dbg(dev->dev, "%s: clk_id=%d, parent_rate=%lu, clk_rate=%lu\n",
+ __func__, info->clk_id, parent_rate, info->rate);
+ parent_div_rate = parent_rate;
+ parent_div_rate_pre = parent_rate;
+
+ /*
+ * The requested clock rate from user space should be respected.
+ * This loop is to search the clock rate that is higher than requested
+ * clock.
+ */
+ while (parent_div_rate >= info->rate) {
+ parent_div_rate_pre = parent_div_rate;
+ parent_div_rate = clk_round_rate(clk, parent_div_rate-1);
+ }
- if (info->flag == TEGRA_CAMERA_ENABLE_PD2VI_CLK) {
- val |= TEGRA_CAMERA_PD2VI_CLK_SEL_VI_SENSOR_CLK;
- }
+ dev_dbg(dev->dev, "%s: set_rate=%lu",
+ __func__, parent_div_rate_pre);
- writel(val, car + offset);
+ clk_set_rate(clk, parent_div_rate_pre);
- val = readl(apb_misc + 0x42c);
- writel(val | 0x1, apb_misc + 0x42c);
+ if (info->clk_id == TEGRA_CAMERA_VI_CLK) {
+ /*
+ * bit 25: 0 = pd2vi_Clk, 1 = vi_sensor_clk
+ * bit 24: 0 = internal clock, 1 = external clock(pd2vi_clk)
+ */
+ if (info->flag == TEGRA_CAMERA_ENABLE_PD2VI_CLK)
+ tegra_clk_cfg_ex(clk, TEGRA_CLK_VI_INP_SEL, 2);
}
info->rate = clk_get_rate(clk);
+ dev_dbg(dev->dev, "%s: get_rate=%lu",
+ __func__, info->rate);
return 0;
}