1fe37b482SAisheng Dong // SPDX-License-Identifier: GPL-2.0+ 2fe37b482SAisheng Dong /* 3fe37b482SAisheng Dong * Copyright 2018 NXP 4fe37b482SAisheng Dong * Dong Aisheng <aisheng.dong@nxp.com> 5fe37b482SAisheng Dong */ 6fe37b482SAisheng Dong 73b9ea606SAnson Huang #include <dt-bindings/firmware/imx/rsrc.h> 83b9ea606SAnson Huang #include <linux/arm-smccc.h> 9fe37b482SAisheng Dong #include <linux/clk-provider.h> 10fe37b482SAisheng Dong #include <linux/err.h> 11fe37b482SAisheng Dong #include <linux/slab.h> 12fe37b482SAisheng Dong 13fe37b482SAisheng Dong #include "clk-scu.h" 14fe37b482SAisheng Dong 153b9ea606SAnson Huang #define IMX_SIP_CPUFREQ 0xC2000001 163b9ea606SAnson Huang #define IMX_SIP_SET_CPUFREQ 0x00 173b9ea606SAnson Huang 18fe37b482SAisheng Dong static struct imx_sc_ipc *ccm_ipc_handle; 19fe37b482SAisheng Dong 20fe37b482SAisheng Dong /* 21fe37b482SAisheng Dong * struct clk_scu - Description of one SCU clock 22fe37b482SAisheng Dong * @hw: the common clk_hw 23fe37b482SAisheng Dong * @rsrc_id: resource ID of this SCU clock 24fe37b482SAisheng Dong * @clk_type: type of this clock resource 25fe37b482SAisheng Dong */ 26fe37b482SAisheng Dong struct clk_scu { 27fe37b482SAisheng Dong struct clk_hw hw; 28fe37b482SAisheng Dong u16 rsrc_id; 29fe37b482SAisheng Dong u8 clk_type; 30fe37b482SAisheng Dong }; 31fe37b482SAisheng Dong 32fe37b482SAisheng Dong /* 33fe37b482SAisheng Dong * struct imx_sc_msg_req_set_clock_rate - clock set rate protocol 34fe37b482SAisheng Dong * @hdr: SCU protocol header 35fe37b482SAisheng Dong * @rate: rate to set 36fe37b482SAisheng Dong * @resource: clock resource to set rate 37fe37b482SAisheng Dong * @clk: clk type of this resource 38fe37b482SAisheng Dong * 39fe37b482SAisheng Dong * This structure describes the SCU protocol of clock rate set 40fe37b482SAisheng Dong */ 41fe37b482SAisheng Dong struct imx_sc_msg_req_set_clock_rate { 42fe37b482SAisheng Dong struct imx_sc_rpc_msg hdr; 43fe37b482SAisheng Dong __le32 rate; 44fe37b482SAisheng Dong __le16 resource; 45fe37b482SAisheng Dong u8 clk; 46fe37b482SAisheng Dong } __packed; 47fe37b482SAisheng Dong 48fe37b482SAisheng Dong struct req_get_clock_rate { 49fe37b482SAisheng Dong __le16 resource; 50fe37b482SAisheng Dong u8 clk; 51fe37b482SAisheng Dong } __packed; 52fe37b482SAisheng Dong 53fe37b482SAisheng Dong struct resp_get_clock_rate { 54fe37b482SAisheng Dong __le32 rate; 55fe37b482SAisheng Dong }; 56fe37b482SAisheng Dong 57fe37b482SAisheng Dong /* 58fe37b482SAisheng Dong * struct imx_sc_msg_get_clock_rate - clock get rate protocol 59fe37b482SAisheng Dong * @hdr: SCU protocol header 60fe37b482SAisheng Dong * @req: get rate request protocol 61fe37b482SAisheng Dong * @resp: get rate response protocol 62fe37b482SAisheng Dong * 63fe37b482SAisheng Dong * This structure describes the SCU protocol of clock rate get 64fe37b482SAisheng Dong */ 65fe37b482SAisheng Dong struct imx_sc_msg_get_clock_rate { 66fe37b482SAisheng Dong struct imx_sc_rpc_msg hdr; 67fe37b482SAisheng Dong union { 68fe37b482SAisheng Dong struct req_get_clock_rate req; 69fe37b482SAisheng Dong struct resp_get_clock_rate resp; 70fe37b482SAisheng Dong } data; 71fe37b482SAisheng Dong }; 72fe37b482SAisheng Dong 73fe37b482SAisheng Dong /* 74666aed2dSAisheng Dong * struct imx_sc_msg_get_clock_parent - clock get parent protocol 75666aed2dSAisheng Dong * @hdr: SCU protocol header 76666aed2dSAisheng Dong * @req: get parent request protocol 77666aed2dSAisheng Dong * @resp: get parent response protocol 78666aed2dSAisheng Dong * 79666aed2dSAisheng Dong * This structure describes the SCU protocol of clock get parent 80666aed2dSAisheng Dong */ 81666aed2dSAisheng Dong struct imx_sc_msg_get_clock_parent { 82666aed2dSAisheng Dong struct imx_sc_rpc_msg hdr; 83666aed2dSAisheng Dong union { 84666aed2dSAisheng Dong struct req_get_clock_parent { 85666aed2dSAisheng Dong __le16 resource; 86666aed2dSAisheng Dong u8 clk; 87666aed2dSAisheng Dong } __packed req; 88666aed2dSAisheng Dong struct resp_get_clock_parent { 89666aed2dSAisheng Dong u8 parent; 90666aed2dSAisheng Dong } resp; 91666aed2dSAisheng Dong } data; 92666aed2dSAisheng Dong }; 93666aed2dSAisheng Dong 94666aed2dSAisheng Dong /* 95666aed2dSAisheng Dong * struct imx_sc_msg_set_clock_parent - clock set parent protocol 96666aed2dSAisheng Dong * @hdr: SCU protocol header 97666aed2dSAisheng Dong * @req: set parent request protocol 98666aed2dSAisheng Dong * 99666aed2dSAisheng Dong * This structure describes the SCU protocol of clock set parent 100666aed2dSAisheng Dong */ 101666aed2dSAisheng Dong struct imx_sc_msg_set_clock_parent { 102666aed2dSAisheng Dong struct imx_sc_rpc_msg hdr; 103666aed2dSAisheng Dong __le16 resource; 104666aed2dSAisheng Dong u8 clk; 105666aed2dSAisheng Dong u8 parent; 106666aed2dSAisheng Dong } __packed; 107666aed2dSAisheng Dong 108666aed2dSAisheng Dong /* 109fe37b482SAisheng Dong * struct imx_sc_msg_req_clock_enable - clock gate protocol 110fe37b482SAisheng Dong * @hdr: SCU protocol header 111fe37b482SAisheng Dong * @resource: clock resource to gate 112fe37b482SAisheng Dong * @clk: clk type of this resource 113fe37b482SAisheng Dong * @enable: whether gate off the clock 114fe37b482SAisheng Dong * @autog: HW auto gate enable 115fe37b482SAisheng Dong * 116fe37b482SAisheng Dong * This structure describes the SCU protocol of clock gate 117fe37b482SAisheng Dong */ 118fe37b482SAisheng Dong struct imx_sc_msg_req_clock_enable { 119fe37b482SAisheng Dong struct imx_sc_rpc_msg hdr; 120fe37b482SAisheng Dong __le16 resource; 121fe37b482SAisheng Dong u8 clk; 122fe37b482SAisheng Dong u8 enable; 123fe37b482SAisheng Dong u8 autog; 124fe37b482SAisheng Dong } __packed; 125fe37b482SAisheng Dong 126fe37b482SAisheng Dong static inline struct clk_scu *to_clk_scu(struct clk_hw *hw) 127fe37b482SAisheng Dong { 128fe37b482SAisheng Dong return container_of(hw, struct clk_scu, hw); 129fe37b482SAisheng Dong } 130fe37b482SAisheng Dong 131fe37b482SAisheng Dong int imx_clk_scu_init(void) 132fe37b482SAisheng Dong { 133fe37b482SAisheng Dong return imx_scu_get_handle(&ccm_ipc_handle); 134fe37b482SAisheng Dong } 135fe37b482SAisheng Dong 136fe37b482SAisheng Dong /* 137fe37b482SAisheng Dong * clk_scu_recalc_rate - Get clock rate for a SCU clock 138fe37b482SAisheng Dong * @hw: clock to get rate for 139fe37b482SAisheng Dong * @parent_rate: parent rate provided by common clock framework, not used 140fe37b482SAisheng Dong * 141fe37b482SAisheng Dong * Gets the current clock rate of a SCU clock. Returns the current 142fe37b482SAisheng Dong * clock rate, or zero in failure. 143fe37b482SAisheng Dong */ 144fe37b482SAisheng Dong static unsigned long clk_scu_recalc_rate(struct clk_hw *hw, 145fe37b482SAisheng Dong unsigned long parent_rate) 146fe37b482SAisheng Dong { 147fe37b482SAisheng Dong struct clk_scu *clk = to_clk_scu(hw); 148fe37b482SAisheng Dong struct imx_sc_msg_get_clock_rate msg; 149fe37b482SAisheng Dong struct imx_sc_rpc_msg *hdr = &msg.hdr; 150fe37b482SAisheng Dong int ret; 151fe37b482SAisheng Dong 152fe37b482SAisheng Dong hdr->ver = IMX_SC_RPC_VERSION; 153fe37b482SAisheng Dong hdr->svc = IMX_SC_RPC_SVC_PM; 154fe37b482SAisheng Dong hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_RATE; 155fe37b482SAisheng Dong hdr->size = 2; 156fe37b482SAisheng Dong 157fe37b482SAisheng Dong msg.data.req.resource = cpu_to_le16(clk->rsrc_id); 158fe37b482SAisheng Dong msg.data.req.clk = clk->clk_type; 159fe37b482SAisheng Dong 160fe37b482SAisheng Dong ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true); 161fe37b482SAisheng Dong if (ret) { 162fe37b482SAisheng Dong pr_err("%s: failed to get clock rate %d\n", 163fe37b482SAisheng Dong clk_hw_get_name(hw), ret); 164fe37b482SAisheng Dong return 0; 165fe37b482SAisheng Dong } 166fe37b482SAisheng Dong 167fe37b482SAisheng Dong return le32_to_cpu(msg.data.resp.rate); 168fe37b482SAisheng Dong } 169fe37b482SAisheng Dong 170fe37b482SAisheng Dong /* 171fe37b482SAisheng Dong * clk_scu_round_rate - Round clock rate for a SCU clock 172fe37b482SAisheng Dong * @hw: clock to round rate for 173fe37b482SAisheng Dong * @rate: rate to round 174fe37b482SAisheng Dong * @parent_rate: parent rate provided by common clock framework, not used 175fe37b482SAisheng Dong * 176fe37b482SAisheng Dong * Returns the current clock rate, or zero in failure. 177fe37b482SAisheng Dong */ 178fe37b482SAisheng Dong static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate, 179fe37b482SAisheng Dong unsigned long *parent_rate) 180fe37b482SAisheng Dong { 181fe37b482SAisheng Dong /* 182fe37b482SAisheng Dong * Assume we support all the requested rate and let the SCU firmware 183fe37b482SAisheng Dong * to handle the left work 184fe37b482SAisheng Dong */ 185fe37b482SAisheng Dong return rate; 186fe37b482SAisheng Dong } 187fe37b482SAisheng Dong 1883b9ea606SAnson Huang static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate, 1893b9ea606SAnson Huang unsigned long parent_rate) 1903b9ea606SAnson Huang { 1913b9ea606SAnson Huang struct clk_scu *clk = to_clk_scu(hw); 1923b9ea606SAnson Huang struct arm_smccc_res res; 1933b9ea606SAnson Huang unsigned long cluster_id; 1943b9ea606SAnson Huang 1953b9ea606SAnson Huang if (clk->rsrc_id == IMX_SC_R_A35) 1963b9ea606SAnson Huang cluster_id = 0; 1973b9ea606SAnson Huang else 1983b9ea606SAnson Huang return -EINVAL; 1993b9ea606SAnson Huang 2003b9ea606SAnson Huang /* CPU frequency scaling can ONLY be done by ARM-Trusted-Firmware */ 2013b9ea606SAnson Huang arm_smccc_smc(IMX_SIP_CPUFREQ, IMX_SIP_SET_CPUFREQ, 2023b9ea606SAnson Huang cluster_id, rate, 0, 0, 0, 0, &res); 2033b9ea606SAnson Huang 2043b9ea606SAnson Huang return 0; 2053b9ea606SAnson Huang } 2063b9ea606SAnson Huang 207fe37b482SAisheng Dong /* 208fe37b482SAisheng Dong * clk_scu_set_rate - Set rate for a SCU clock 209fe37b482SAisheng Dong * @hw: clock to change rate for 210fe37b482SAisheng Dong * @rate: target rate for the clock 211fe37b482SAisheng Dong * @parent_rate: rate of the clock parent, not used for SCU clocks 212fe37b482SAisheng Dong * 213fe37b482SAisheng Dong * Sets a clock frequency for a SCU clock. Returns the SCU 214fe37b482SAisheng Dong * protocol status. 215fe37b482SAisheng Dong */ 216fe37b482SAisheng Dong static int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate, 217fe37b482SAisheng Dong unsigned long parent_rate) 218fe37b482SAisheng Dong { 219fe37b482SAisheng Dong struct clk_scu *clk = to_clk_scu(hw); 220fe37b482SAisheng Dong struct imx_sc_msg_req_set_clock_rate msg; 221fe37b482SAisheng Dong struct imx_sc_rpc_msg *hdr = &msg.hdr; 222fe37b482SAisheng Dong 223fe37b482SAisheng Dong hdr->ver = IMX_SC_RPC_VERSION; 224fe37b482SAisheng Dong hdr->svc = IMX_SC_RPC_SVC_PM; 225fe37b482SAisheng Dong hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_RATE; 226fe37b482SAisheng Dong hdr->size = 3; 227fe37b482SAisheng Dong 228fe37b482SAisheng Dong msg.rate = cpu_to_le32(rate); 229fe37b482SAisheng Dong msg.resource = cpu_to_le16(clk->rsrc_id); 230fe37b482SAisheng Dong msg.clk = clk->clk_type; 231fe37b482SAisheng Dong 232fe37b482SAisheng Dong return imx_scu_call_rpc(ccm_ipc_handle, &msg, true); 233fe37b482SAisheng Dong } 234fe37b482SAisheng Dong 235666aed2dSAisheng Dong static u8 clk_scu_get_parent(struct clk_hw *hw) 236666aed2dSAisheng Dong { 237666aed2dSAisheng Dong struct clk_scu *clk = to_clk_scu(hw); 238666aed2dSAisheng Dong struct imx_sc_msg_get_clock_parent msg; 239666aed2dSAisheng Dong struct imx_sc_rpc_msg *hdr = &msg.hdr; 240666aed2dSAisheng Dong int ret; 241666aed2dSAisheng Dong 242666aed2dSAisheng Dong hdr->ver = IMX_SC_RPC_VERSION; 243666aed2dSAisheng Dong hdr->svc = IMX_SC_RPC_SVC_PM; 244666aed2dSAisheng Dong hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_PARENT; 245666aed2dSAisheng Dong hdr->size = 2; 246666aed2dSAisheng Dong 247666aed2dSAisheng Dong msg.data.req.resource = cpu_to_le16(clk->rsrc_id); 248666aed2dSAisheng Dong msg.data.req.clk = clk->clk_type; 249666aed2dSAisheng Dong 250666aed2dSAisheng Dong ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true); 251666aed2dSAisheng Dong if (ret) { 252666aed2dSAisheng Dong pr_err("%s: failed to get clock parent %d\n", 253666aed2dSAisheng Dong clk_hw_get_name(hw), ret); 254666aed2dSAisheng Dong return 0; 255666aed2dSAisheng Dong } 256666aed2dSAisheng Dong 257666aed2dSAisheng Dong return msg.data.resp.parent; 258666aed2dSAisheng Dong } 259666aed2dSAisheng Dong 260666aed2dSAisheng Dong static int clk_scu_set_parent(struct clk_hw *hw, u8 index) 261666aed2dSAisheng Dong { 262666aed2dSAisheng Dong struct clk_scu *clk = to_clk_scu(hw); 263666aed2dSAisheng Dong struct imx_sc_msg_set_clock_parent msg; 264666aed2dSAisheng Dong struct imx_sc_rpc_msg *hdr = &msg.hdr; 265666aed2dSAisheng Dong 266666aed2dSAisheng Dong hdr->ver = IMX_SC_RPC_VERSION; 267666aed2dSAisheng Dong hdr->svc = IMX_SC_RPC_SVC_PM; 268666aed2dSAisheng Dong hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_PARENT; 269666aed2dSAisheng Dong hdr->size = 2; 270666aed2dSAisheng Dong 271666aed2dSAisheng Dong msg.resource = cpu_to_le16(clk->rsrc_id); 272666aed2dSAisheng Dong msg.clk = clk->clk_type; 273666aed2dSAisheng Dong msg.parent = index; 274666aed2dSAisheng Dong 275666aed2dSAisheng Dong return imx_scu_call_rpc(ccm_ipc_handle, &msg, true); 276666aed2dSAisheng Dong } 277666aed2dSAisheng Dong 278fe37b482SAisheng Dong static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource, 279fe37b482SAisheng Dong u8 clk, bool enable, bool autog) 280fe37b482SAisheng Dong { 281fe37b482SAisheng Dong struct imx_sc_msg_req_clock_enable msg; 282fe37b482SAisheng Dong struct imx_sc_rpc_msg *hdr = &msg.hdr; 283fe37b482SAisheng Dong 284fe37b482SAisheng Dong hdr->ver = IMX_SC_RPC_VERSION; 285fe37b482SAisheng Dong hdr->svc = IMX_SC_RPC_SVC_PM; 286fe37b482SAisheng Dong hdr->func = IMX_SC_PM_FUNC_CLOCK_ENABLE; 287fe37b482SAisheng Dong hdr->size = 3; 288fe37b482SAisheng Dong 289fe37b482SAisheng Dong msg.resource = cpu_to_le16(resource); 290fe37b482SAisheng Dong msg.clk = clk; 291fe37b482SAisheng Dong msg.enable = enable; 292fe37b482SAisheng Dong msg.autog = autog; 293fe37b482SAisheng Dong 294fe37b482SAisheng Dong return imx_scu_call_rpc(ccm_ipc_handle, &msg, true); 295fe37b482SAisheng Dong } 296fe37b482SAisheng Dong 297fe37b482SAisheng Dong /* 298fe37b482SAisheng Dong * clk_scu_prepare - Enable a SCU clock 299fe37b482SAisheng Dong * @hw: clock to enable 300fe37b482SAisheng Dong * 301fe37b482SAisheng Dong * Enable the clock at the DSC slice level 302fe37b482SAisheng Dong */ 303fe37b482SAisheng Dong static int clk_scu_prepare(struct clk_hw *hw) 304fe37b482SAisheng Dong { 305fe37b482SAisheng Dong struct clk_scu *clk = to_clk_scu(hw); 306fe37b482SAisheng Dong 307fe37b482SAisheng Dong return sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id, 308fe37b482SAisheng Dong clk->clk_type, true, false); 309fe37b482SAisheng Dong } 310fe37b482SAisheng Dong 311fe37b482SAisheng Dong /* 312fe37b482SAisheng Dong * clk_scu_unprepare - Disable a SCU clock 313fe37b482SAisheng Dong * @hw: clock to enable 314fe37b482SAisheng Dong * 315fe37b482SAisheng Dong * Disable the clock at the DSC slice level 316fe37b482SAisheng Dong */ 317fe37b482SAisheng Dong static void clk_scu_unprepare(struct clk_hw *hw) 318fe37b482SAisheng Dong { 319fe37b482SAisheng Dong struct clk_scu *clk = to_clk_scu(hw); 320fe37b482SAisheng Dong int ret; 321fe37b482SAisheng Dong 322fe37b482SAisheng Dong ret = sc_pm_clock_enable(ccm_ipc_handle, clk->rsrc_id, 323fe37b482SAisheng Dong clk->clk_type, false, false); 324fe37b482SAisheng Dong if (ret) 325fe37b482SAisheng Dong pr_warn("%s: clk unprepare failed %d\n", clk_hw_get_name(hw), 326fe37b482SAisheng Dong ret); 327fe37b482SAisheng Dong } 328fe37b482SAisheng Dong 329fe37b482SAisheng Dong static const struct clk_ops clk_scu_ops = { 330fe37b482SAisheng Dong .recalc_rate = clk_scu_recalc_rate, 331fe37b482SAisheng Dong .round_rate = clk_scu_round_rate, 332fe37b482SAisheng Dong .set_rate = clk_scu_set_rate, 333666aed2dSAisheng Dong .get_parent = clk_scu_get_parent, 334666aed2dSAisheng Dong .set_parent = clk_scu_set_parent, 335fe37b482SAisheng Dong .prepare = clk_scu_prepare, 336fe37b482SAisheng Dong .unprepare = clk_scu_unprepare, 337fe37b482SAisheng Dong }; 338fe37b482SAisheng Dong 3393b9ea606SAnson Huang static const struct clk_ops clk_scu_cpu_ops = { 3403b9ea606SAnson Huang .recalc_rate = clk_scu_recalc_rate, 3413b9ea606SAnson Huang .round_rate = clk_scu_round_rate, 3423b9ea606SAnson Huang .set_rate = clk_scu_atf_set_cpu_rate, 3433b9ea606SAnson Huang .prepare = clk_scu_prepare, 3443b9ea606SAnson Huang .unprepare = clk_scu_unprepare, 3453b9ea606SAnson Huang }; 3463b9ea606SAnson Huang 347666aed2dSAisheng Dong struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents, 348666aed2dSAisheng Dong int num_parents, u32 rsrc_id, u8 clk_type) 349fe37b482SAisheng Dong { 350fe37b482SAisheng Dong struct clk_init_data init; 351fe37b482SAisheng Dong struct clk_scu *clk; 352fe37b482SAisheng Dong struct clk_hw *hw; 353fe37b482SAisheng Dong int ret; 354fe37b482SAisheng Dong 355fe37b482SAisheng Dong clk = kzalloc(sizeof(*clk), GFP_KERNEL); 356fe37b482SAisheng Dong if (!clk) 357fe37b482SAisheng Dong return ERR_PTR(-ENOMEM); 358fe37b482SAisheng Dong 359fe37b482SAisheng Dong clk->rsrc_id = rsrc_id; 360fe37b482SAisheng Dong clk->clk_type = clk_type; 361fe37b482SAisheng Dong 362fe37b482SAisheng Dong init.name = name; 363fe37b482SAisheng Dong init.ops = &clk_scu_ops; 3643b9ea606SAnson Huang if (rsrc_id == IMX_SC_R_A35) 3653b9ea606SAnson Huang init.ops = &clk_scu_cpu_ops; 3663b9ea606SAnson Huang else 3673b9ea606SAnson Huang init.ops = &clk_scu_ops; 368666aed2dSAisheng Dong init.parent_names = parents; 369666aed2dSAisheng Dong init.num_parents = num_parents; 370666aed2dSAisheng Dong 371fe37b482SAisheng Dong /* 372fe37b482SAisheng Dong * Note on MX8, the clocks are tightly coupled with power domain 373fe37b482SAisheng Dong * that once the power domain is off, the clock status may be 374fe37b482SAisheng Dong * lost. So we make it NOCACHE to let user to retrieve the real 375fe37b482SAisheng Dong * clock status from HW instead of using the possible invalid 376fe37b482SAisheng Dong * cached rate. 377fe37b482SAisheng Dong */ 378fe37b482SAisheng Dong init.flags = CLK_GET_RATE_NOCACHE; 379fe37b482SAisheng Dong clk->hw.init = &init; 380fe37b482SAisheng Dong 381fe37b482SAisheng Dong hw = &clk->hw; 382fe37b482SAisheng Dong ret = clk_hw_register(NULL, hw); 383fe37b482SAisheng Dong if (ret) { 384fe37b482SAisheng Dong kfree(clk); 385fe37b482SAisheng Dong hw = ERR_PTR(ret); 386fe37b482SAisheng Dong } 387fe37b482SAisheng Dong 388fe37b482SAisheng Dong return hw; 389fe37b482SAisheng Dong } 390