clk: imx: scu: add set parent support
[linux-2.6-microblaze.git] / drivers / clk / imx / clk-scu.c
index 7ccf7ed..f460526 100644 (file)
@@ -65,6 +65,41 @@ struct imx_sc_msg_get_clock_rate {
        } data;
 };
 
+/*
+ * struct imx_sc_msg_get_clock_parent - clock get parent protocol
+ * @hdr: SCU protocol header
+ * @req: get parent request protocol
+ * @resp: get parent response protocol
+ *
+ * This structure describes the SCU protocol of clock get parent
+ */
+struct imx_sc_msg_get_clock_parent {
+       struct imx_sc_rpc_msg hdr;
+       union {
+               struct req_get_clock_parent {
+                       __le16 resource;
+                       u8 clk;
+               } __packed req;
+               struct resp_get_clock_parent {
+                       u8 parent;
+               } resp;
+       } data;
+};
+
+/*
+ * struct imx_sc_msg_set_clock_parent - clock set parent protocol
+ * @hdr: SCU protocol header
+ * @req: set parent request protocol
+ *
+ * This structure describes the SCU protocol of clock set parent
+ */
+struct imx_sc_msg_set_clock_parent {
+       struct imx_sc_rpc_msg hdr;
+       __le16 resource;
+       u8 clk;
+       u8 parent;
+} __packed;
+
 /*
  * struct imx_sc_msg_req_clock_enable - clock gate protocol
  * @hdr: SCU protocol header
@@ -173,6 +208,49 @@ static int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate,
        return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
 }
 
+static u8 clk_scu_get_parent(struct clk_hw *hw)
+{
+       struct clk_scu *clk = to_clk_scu(hw);
+       struct imx_sc_msg_get_clock_parent msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+       int ret;
+
+       hdr->ver = IMX_SC_RPC_VERSION;
+       hdr->svc = IMX_SC_RPC_SVC_PM;
+       hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_PARENT;
+       hdr->size = 2;
+
+       msg.data.req.resource = cpu_to_le16(clk->rsrc_id);
+       msg.data.req.clk = clk->clk_type;
+
+       ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+       if (ret) {
+               pr_err("%s: failed to get clock parent %d\n",
+                      clk_hw_get_name(hw), ret);
+               return 0;
+       }
+
+       return msg.data.resp.parent;
+}
+
+static int clk_scu_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct clk_scu *clk = to_clk_scu(hw);
+       struct imx_sc_msg_set_clock_parent msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+
+       hdr->ver = IMX_SC_RPC_VERSION;
+       hdr->svc = IMX_SC_RPC_SVC_PM;
+       hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_PARENT;
+       hdr->size = 2;
+
+       msg.resource = cpu_to_le16(clk->rsrc_id);
+       msg.clk = clk->clk_type;
+       msg.parent = index;
+
+       return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
+}
+
 static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource,
                              u8 clk, bool enable, bool autog)
 {
@@ -228,11 +306,14 @@ static const struct clk_ops clk_scu_ops = {
        .recalc_rate = clk_scu_recalc_rate,
        .round_rate = clk_scu_round_rate,
        .set_rate = clk_scu_set_rate,
+       .get_parent = clk_scu_get_parent,
+       .set_parent = clk_scu_set_parent,
        .prepare = clk_scu_prepare,
        .unprepare = clk_scu_unprepare,
 };
 
-struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type)
+struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
+                            int num_parents, u32 rsrc_id, u8 clk_type)
 {
        struct clk_init_data init;
        struct clk_scu *clk;
@@ -248,7 +329,9 @@ struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type)
 
        init.name = name;
        init.ops = &clk_scu_ops;
-       init.num_parents = 0;
+       init.parent_names = parents;
+       init.num_parents = num_parents;
+
        /*
         * Note on MX8, the clocks are tightly coupled with power domain
         * that once the power domain is off, the clock status may be