|
@@ -95,3 +95,108 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
|
|
|
int ena = 0, i = 0;
|
|
|
u8 cm_idlest_reg;
|
|
|
u32 mask;
|
|
|
+
|
|
|
+ if (!idlest_id || (idlest_id > ARRAY_SIZE(omap3xxx_cm_idlest_offs)))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ cm_idlest_reg = omap3xxx_cm_idlest_offs[idlest_id - 1];
|
|
|
+
|
|
|
+ mask = 1 << idlest_shift;
|
|
|
+ ena = 0;
|
|
|
+
|
|
|
+ omap_test_timeout(((omap2_cm_read_mod_reg(prcm_mod, cm_idlest_reg) &
|
|
|
+ mask) == ena), MAX_MODULE_READY_TIME, i);
|
|
|
+
|
|
|
+ return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap3xxx_cm_split_idlest_reg - split CM_IDLEST reg addr into its components
|
|
|
+ * @idlest_reg: CM_IDLEST* virtual address
|
|
|
+ * @prcm_inst: pointer to an s16 to return the PRCM instance offset
|
|
|
+ * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID
|
|
|
+ *
|
|
|
+ * XXX This function is only needed until absolute register addresses are
|
|
|
+ * removed from the OMAP struct clk records.
|
|
|
+ */
|
|
|
+int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
|
|
|
+ u8 *idlest_reg_id)
|
|
|
+{
|
|
|
+ unsigned long offs;
|
|
|
+ u8 idlest_offs;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (idlest_reg < (cm_base + OMAP3430_IVA2_MOD) ||
|
|
|
+ idlest_reg > (cm_base + 0x1ffff))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ idlest_offs = (unsigned long)idlest_reg & 0xff;
|
|
|
+ for (i = 0; i < ARRAY_SIZE(omap3xxx_cm_idlest_offs); i++) {
|
|
|
+ if (idlest_offs == omap3xxx_cm_idlest_offs[i]) {
|
|
|
+ *idlest_reg_id = i + 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i == ARRAY_SIZE(omap3xxx_cm_idlest_offs))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ offs = idlest_reg - cm_base;
|
|
|
+ offs &= 0xff00;
|
|
|
+ *prcm_inst = offs;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* Clockdomain low-level operations */
|
|
|
+
|
|
|
+static int omap3xxx_clkdm_add_sleepdep(struct clockdomain *clkdm1,
|
|
|
+ struct clockdomain *clkdm2)
|
|
|
+{
|
|
|
+ omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
|
|
|
+ clkdm1->pwrdm.ptr->prcm_offs,
|
|
|
+ OMAP3430_CM_SLEEPDEP);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int omap3xxx_clkdm_del_sleepdep(struct clockdomain *clkdm1,
|
|
|
+ struct clockdomain *clkdm2)
|
|
|
+{
|
|
|
+ omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
|
|
|
+ clkdm1->pwrdm.ptr->prcm_offs,
|
|
|
+ OMAP3430_CM_SLEEPDEP);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int omap3xxx_clkdm_read_sleepdep(struct clockdomain *clkdm1,
|
|
|
+ struct clockdomain *clkdm2)
|
|
|
+{
|
|
|
+ return omap2_cm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
|
|
|
+ OMAP3430_CM_SLEEPDEP,
|
|
|
+ (1 << clkdm2->dep_bit));
|
|
|
+}
|
|
|
+
|
|
|
+static int omap3xxx_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
|
|
|
+{
|
|
|
+ struct clkdm_dep *cd;
|
|
|
+ u32 mask = 0;
|
|
|
+
|
|
|
+ for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
|
|
|
+ if (!cd->clkdm)
|
|
|
+ continue; /* only happens if data is erroneous */
|
|
|
+
|
|
|
+ mask |= 1 << cd->clkdm->dep_bit;
|
|
|
+ atomic_set(&cd->sleepdep_usecount, 0);
|
|
|
+ }
|
|
|
+ omap2_cm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
|
|
|
+ OMAP3430_CM_SLEEPDEP);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int omap3xxx_clkdm_sleep(struct clockdomain *clkdm)
|
|
|
+{
|
|
|
+ omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
|
|
|
+ clkdm->clktrctrl_mask);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|