X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fmailbox%2Fscpi_protocol.c;h=872823172ea2ab5bb488532fd0a0d8fa609b378f;hb=6168e92bdd527b4cd8bc1f0125611e9fcc361695;hp=d906906fdbd71dc66f8705703281adf2a0e06f25;hpb=e82146650ea5de8205f8890eaf4cb98615c51d9a;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/mailbox/scpi_protocol.c b/drivers/mailbox/scpi_protocol.c index d906906fdbd7..872823172ea2 100644 --- a/drivers/mailbox/scpi_protocol.c +++ b/drivers/mailbox/scpi_protocol.c @@ -2,7 +2,7 @@ * System Control and Power Interface (SCPI) Message Protocol driver * * Copyright (C) 2014 ARM Ltd. - * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd + * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -24,12 +24,11 @@ #include #include #include -#include #include -#include -#include +#include +#include -#include "scpi_cmd.h" +#define SCPI_VERSION 0x01000002 /* version: 1.0.0.2 */ #define CMD_ID_SHIFT 0 #define CMD_ID_MASK 0xff @@ -48,11 +47,96 @@ #define DVFS_LATENCY(hdr) ((hdr) >> 16) #define DVFS_OPP_COUNT(hdr) (((hdr) >> 8) & 0xff) -struct scpi_data_buf { - int client_id; - struct rockchip_mbox_msg *data; - struct completion complete; - int timeout_ms; +static int max_chan_num = 0; +static DECLARE_BITMAP(bm_mbox_chans, 4); +static DEFINE_MUTEX(scpi_mtx); + +enum scpi_error_codes { + SCPI_SUCCESS = 0, /* Success */ + SCPI_ERR_PARAM = 1, /* Invalid parameter(s) */ + SCPI_ERR_ALIGN = 2, /* Invalid alignment */ + SCPI_ERR_SIZE = 3, /* Invalid size */ + SCPI_ERR_HANDLER = 4, /* Invalid handler/callback */ + SCPI_ERR_ACCESS = 5, /* Invalid access/permission denied */ + SCPI_ERR_RANGE = 6, /* Value out of range */ + SCPI_ERR_TIMEOUT = 7, /* Timeout has occurred */ + SCPI_ERR_NOMEM = 8, /* Invalid memory area or pointer */ + SCPI_ERR_PWRSTATE = 9, /* Invalid power state */ + SCPI_ERR_SUPPORT = 10, /* Not supported or disabled */ + SCPI_ERR_DEVICE = 11, /* Device error */ + SCPI_ERR_MAX +}; + +enum scpi_client_id { + SCPI_CL_NONE, + SCPI_CL_CLOCKS, + SCPI_CL_DVFS, + SCPI_CL_POWER, + SCPI_CL_THERMAL, + SCPI_CL_DDR, + SCPI_CL_SYS, + SCPI_MAX, +}; + +enum scpi_ddr_cmd { + SCPI_DDR_INIT, + SCPI_DDR_SET_FREQ, + SCPI_DDR_ROUND_RATE, + SCPI_DDR_AUTO_SELF_REFRESH, + SCPI_DDR_BANDWIDTH_GET, + SCPI_DDR_GET_FREQ, + SCPI_DDR_SEND_TIMING, + SCPI_DDR_DCLK_MODE, +}; + +enum scpi_sys_cmd { + SCPI_SYS_GET_VERSION, + SCPI_SYS_REFRESH_MCU_FREQ, + SCPI_SYS_SET_MCU_STATE_SUSPEND, + SCPI_SYS_SET_MCU_STATE_RESUME, + SCPI_SYS_SET_JTAGMUX_ON_OFF, +}; + +enum scpi_std_cmd { + SCPI_CMD_INVALID = 0x00, + SCPI_CMD_SCPI_READY = 0x01, + SCPI_CMD_SCPI_CAPABILITIES = 0x02, + SCPI_CMD_EVENT = 0x03, + SCPI_CMD_SET_CSS_PWR_STATE = 0x04, + SCPI_CMD_GET_CSS_PWR_STATE = 0x05, + SCPI_CMD_CFG_PWR_STATE_STAT = 0x06, + SCPI_CMD_GET_PWR_STATE_STAT = 0x07, + SCPI_CMD_SYS_PWR_STATE = 0x08, + SCPI_CMD_L2_READY = 0x09, + SCPI_CMD_SET_AP_TIMER = 0x0a, + SCPI_CMD_CANCEL_AP_TIME = 0x0b, + SCPI_CMD_DVFS_CAPABILITIES = 0x0c, + SCPI_CMD_GET_DVFS_INFO = 0x0d, + SCPI_CMD_SET_DVFS = 0x0e, + SCPI_CMD_GET_DVFS = 0x0f, + SCPI_CMD_GET_DVFS_STAT = 0x10, + SCPI_CMD_SET_RTC = 0x11, + SCPI_CMD_GET_RTC = 0x12, + SCPI_CMD_CLOCK_CAPABILITIES = 0x13, + SCPI_CMD_SET_CLOCK_INDEX = 0x14, + SCPI_CMD_SET_CLOCK_VALUE = 0x15, + SCPI_CMD_GET_CLOCK_VALUE = 0x16, + SCPI_CMD_PSU_CAPABILITIES = 0x17, + SCPI_CMD_SET_PSU = 0x18, + SCPI_CMD_GET_PSU = 0x19, + SCPI_CMD_SENSOR_CAPABILITIES = 0x1a, + SCPI_CMD_SENSOR_INFO = 0x1b, + SCPI_CMD_SENSOR_VALUE = 0x1c, + SCPI_CMD_SENSOR_CFG_PERIODIC = 0x1d, + SCPI_CMD_SENSOR_CFG_BOUNDS = 0x1e, + SCPI_CMD_SENSOR_ASYNC_VALUE = 0x1f, + SCPI_CMD_COUNT +}; + +enum scpi_thermal_cmd { + SCPI_THERMAL_GET_TSADC_DATA, + SCPI_THERMAL_SET_TSADC_CYCLE, + SCPI_THERMAL_COUNT }; static int high_priority_cmds[] = { @@ -72,6 +156,18 @@ static int high_priority_cmds[] = { SCPI_CMD_SENSOR_CFG_BOUNDS, }; +struct scpi_data_buf { + int client_id; + struct rk3368_mbox_msg *data; + struct completion complete; + int timeout_ms; +}; + +struct scpi_mcu_ver { + u32 scpi_ver; + char mcu_ver[16]; +}; + static struct scpi_opp *scpi_opps[MAX_DVFS_DOMAINS]; static struct device *the_scpi_device; @@ -89,7 +185,7 @@ static inline int scpi_to_linux_errno(int errno) return -EIO; } -static bool high_priority_chan_supported(int cmd) +static bool __maybe_unused high_priority_chan_supported(int cmd) { int idx; @@ -99,19 +195,50 @@ static bool high_priority_chan_supported(int cmd) return false; } +static int scpi_alloc_mbox_chan(void) +{ + int index; + + mutex_lock(&scpi_mtx); + + index = find_first_zero_bit(bm_mbox_chans, max_chan_num); + if (index >= max_chan_num) { + pr_err("alloc mailbox channel failed\n"); + mutex_unlock(&scpi_mtx); + return -EBUSY; + } + + set_bit(index, bm_mbox_chans); + + mutex_unlock(&scpi_mtx); + return index; +} + +static void scpi_free_mbox_chan(int chan) +{ + int index = chan; + + mutex_lock(&scpi_mtx); + + if (index < max_chan_num && index >= 0) + clear_bit(index, bm_mbox_chans); + + mutex_unlock(&scpi_mtx); +} + static void scpi_rx_callback(struct mbox_client *cl, void *msg) { - struct rockchip_mbox_msg *data = (struct rockchip_mbox_msg *)msg; + struct rk3368_mbox_msg *data = (struct rk3368_mbox_msg *)msg; struct scpi_data_buf *scpi_buf = data->cl_data; complete(&scpi_buf->complete); } -static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, bool high_priority) +static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, int index) { struct mbox_chan *chan; struct mbox_client cl; - struct rockchip_mbox_msg *data = scpi_buf->data; + struct rk3368_mbox_msg *data = scpi_buf->data; u32 status; int ret; int timeout = msecs_to_jiffies(scpi_buf->timeout_ms); @@ -124,12 +251,15 @@ static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, bool high_priority) cl.dev = the_scpi_device; cl.rx_callback = scpi_rx_callback; cl.tx_done = NULL; + cl.tx_prepare = NULL; cl.tx_block = false; cl.knows_txdone = false; - chan = mbox_request_channel(&cl, high_priority); - if (IS_ERR(chan)) + chan = mbox_request_channel(&cl, index); + if (IS_ERR(chan)) { + scpi_free_mbox_chan(index); return PTR_ERR(chan); + } init_completion(&scpi_buf->complete); if (mbox_send_message(chan, (void *)data) < 0) { @@ -146,6 +276,7 @@ static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, bool high_priority) free_channel: mbox_free_channel(chan); + scpi_free_mbox_chan(index); return scpi_to_linux_errno(status); } @@ -153,7 +284,7 @@ free_channel: #define SCPI_SETUP_DBUF(scpi_buf, mbox_buf, _client_id,\ _cmd, _tx_buf, _rx_buf) \ do { \ - struct rockchip_mbox_msg *pdata = &mbox_buf; \ + struct rk3368_mbox_msg *pdata = &mbox_buf; \ pdata->cmd = _cmd; \ pdata->tx_buf = &_tx_buf; \ pdata->tx_size = sizeof(_tx_buf); \ @@ -164,27 +295,44 @@ do { \ scpi_buf.timeout_ms = SCPI_CMD_DEFAULT_TIMEOUT_MS; \ } while (0) +#define SCPI_SETUP_DBUF_BY_SIZE(scpi_buf, mbox_buf, _client_id, \ + _cmd, _tx_buf, _tx_size, _rx_buf) \ +do { \ + struct rk3368_mbox_msg *pdata = &mbox_buf; \ + pdata->cmd = _cmd; \ + pdata->tx_buf = _tx_buf; \ + pdata->tx_size = _tx_size; \ + pdata->rx_buf = &_rx_buf; \ + pdata->rx_size = sizeof(_rx_buf); \ + scpi_buf.client_id = _client_id; \ + scpi_buf.data = pdata; \ + scpi_buf.timeout_ms = SCPI_CMD_DEFAULT_TIMEOUT_MS; \ +} while (0) + static int scpi_execute_cmd(struct scpi_data_buf *scpi_buf) { - struct rockchip_mbox_msg *data; - bool high_priority; + struct rk3368_mbox_msg *data; + int index; if (!scpi_buf || !scpi_buf->data) return -EINVAL; + index = scpi_alloc_mbox_chan(); + if (index < 0) + return -EBUSY; + data = scpi_buf->data; - high_priority = high_priority_chan_supported(data->cmd); data->cmd = PACK_SCPI_CMD(data->cmd, scpi_buf->client_id, data->tx_size); data->cl_data = scpi_buf; - return send_scpi_cmd(scpi_buf, high_priority); + return send_scpi_cmd(scpi_buf, index); } unsigned long scpi_clk_get_val(u16 clk_id) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed { u32 status; u32 clk_rate; @@ -202,7 +350,7 @@ EXPORT_SYMBOL_GPL(scpi_clk_get_val); int scpi_clk_set_val(u16 clk_id, unsigned long rate) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; int stat; struct __packed { u32 clk_rate; @@ -221,7 +369,7 @@ EXPORT_SYMBOL_GPL(scpi_clk_set_val); struct scpi_opp *scpi_dvfs_get_opps(u8 domain) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed { u32 status; u32 header; @@ -268,7 +416,7 @@ EXPORT_SYMBOL_GPL(scpi_dvfs_get_opps); int scpi_dvfs_get_idx(u8 domain) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed { u32 status; u8 dvfs_idx; @@ -291,7 +439,7 @@ EXPORT_SYMBOL_GPL(scpi_dvfs_get_idx); int scpi_dvfs_set_idx(u8 domain, u8 idx) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed { u8 dvfs_domain; u8 dvfs_idx; @@ -313,7 +461,7 @@ EXPORT_SYMBOL_GPL(scpi_dvfs_set_idx); int scpi_get_sensor(char *name) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed { u32 status; u16 sensors; @@ -330,7 +478,7 @@ int scpi_get_sensor(char *name) /* This should be handled by a generic macro */ do { - struct rockchip_mbox_msg *pdata = &mdata; + struct rk3368_mbox_msg *pdata = &mdata; pdata->cmd = SCPI_CMD_SENSOR_CAPABILITIES; pdata->tx_size = 0; @@ -365,7 +513,7 @@ EXPORT_SYMBOL_GPL(scpi_get_sensor); int scpi_get_sensor_value(u16 sensor, u32 *val) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed { u32 status; u32 val; @@ -383,30 +531,36 @@ int scpi_get_sensor_value(u16 sensor, u32 *val) } EXPORT_SYMBOL_GPL(scpi_get_sensor_value); -static int scpi_get_version(u32 old, u32 *ver) +static int scpi_get_version(u32 old, struct scpi_mcu_ver *ver) { + int ret; struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed { u32 status; - u32 ver; + struct scpi_mcu_ver version; } buf; - int ret; + memset(&buf, 0, sizeof(buf)); SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_SYS, SCPI_SYS_GET_VERSION, old, buf); ret = scpi_execute_cmd(&sdata); - if (ret) - *ver = buf.ver; + if (ret) { + pr_err("get scpi version from MCU failed, ret=%d\n", ret); + goto OUT; + } + + memcpy(ver, &(buf.version), sizeof(*ver)); +OUT: return ret; } int scpi_sys_set_mcu_state_suspend(void) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed1 { u32 status; } tx_buf; @@ -424,7 +578,7 @@ EXPORT_SYMBOL_GPL(scpi_sys_set_mcu_state_suspend); int scpi_sys_set_mcu_state_resume(void) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed1 { u32 status; } tx_buf; @@ -440,14 +594,60 @@ int scpi_sys_set_mcu_state_resume(void) } EXPORT_SYMBOL_GPL(scpi_sys_set_mcu_state_resume); -int scpi_ddr_init(u32 dram_speed_bin, u32 freq, u32 lcdc_type) +int scpi_sys_set_jtagmux_on_off(u32 en) +{ + int ret; + struct scpi_data_buf sdata; + struct rk3368_mbox_msg mdata; + struct __packed1 { + u32 enable; + } tx_buf; + + struct __packed2 { + u32 status; + } rx_buf; + + tx_buf.enable = en; + SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_SYS, + SCPI_SYS_SET_JTAGMUX_ON_OFF, tx_buf, rx_buf); + + ret = scpi_execute_cmd(&sdata); + if (ret) + pr_err("set jtagmux on-off failed, ret=%d\n", ret); + else + ret = rx_buf.status; + + return ret; +} +EXPORT_SYMBOL_GPL(scpi_sys_set_jtagmux_on_off); + +int scpi_ddr_dclk_mode(u32 dclk_mode) +{ + struct scpi_data_buf sdata; + struct rk3368_mbox_msg mdata; + struct __packed1 { + u32 dclk_mode; + } tx_buf; + struct __packed2 { + u32 status; + } rx_buf; + + tx_buf.dclk_mode = (u32)dclk_mode; + SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR, + SCPI_DDR_DCLK_MODE, tx_buf, rx_buf); + return scpi_execute_cmd(&sdata); +} +EXPORT_SYMBOL_GPL(scpi_ddr_dclk_mode); + +int scpi_ddr_init(u32 dram_speed_bin, u32 freq, u32 lcdc_type, u32 addr_mcu_el3) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed1 { u32 dram_speed_bin; u32 freq; u32 lcdc_type; + u32 addr_mcu_el3; } tx_buf; struct __packed2 { u32 status; @@ -456,36 +656,60 @@ int scpi_ddr_init(u32 dram_speed_bin, u32 freq, u32 lcdc_type) tx_buf.dram_speed_bin = (u32)dram_speed_bin; tx_buf.freq = (u32)freq; tx_buf.lcdc_type = (u32)lcdc_type; - + tx_buf.addr_mcu_el3 = addr_mcu_el3; SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR, SCPI_DDR_INIT, tx_buf, rx_buf); return scpi_execute_cmd(&sdata); } EXPORT_SYMBOL_GPL(scpi_ddr_init); -int scpi_ddr_set_clk_rate(u32 rate) +int scpi_ddr_set_clk_rate(u32 rate, u32 lcdc_type) { + int ret; + struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed1 { u32 clk_rate; + u32 lcdc_type; } tx_buf; struct __packed2 { u32 status; + u32 freq; } rx_buf; tx_buf.clk_rate = (u32)rate; - + tx_buf.lcdc_type = (u32)lcdc_type; SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR, SCPI_DDR_SET_FREQ, tx_buf, rx_buf); - return scpi_execute_cmd(&sdata); + ret = scpi_execute_cmd(&sdata); + + if ((!ret) && (!rx_buf.status)) + ret = rx_buf.freq; + else + ret = 0; + + return ret; } EXPORT_SYMBOL_GPL(scpi_ddr_set_clk_rate); +int scpi_ddr_send_timing(u32 *p, u32 size) +{ + struct scpi_data_buf sdata; + struct rk3368_mbox_msg mdata; + struct __packed2 { + u32 status; + } rx_buf; + SCPI_SETUP_DBUF_BY_SIZE(sdata, mdata, SCPI_CL_DDR, + SCPI_DDR_SEND_TIMING, p, size, rx_buf); + return scpi_execute_cmd(&sdata); +} +EXPORT_SYMBOL_GPL(scpi_ddr_send_timing); + int scpi_ddr_round_rate(u32 m_hz) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed1 { u32 clk_rate; } tx_buf; @@ -508,7 +732,7 @@ EXPORT_SYMBOL_GPL(scpi_ddr_round_rate); int scpi_ddr_set_auto_self_refresh(u32 en) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed1 { u32 enable; } tx_buf; @@ -528,7 +752,7 @@ int scpi_ddr_bandwidth_get(struct ddr_bw_info *ddr_bw_ch0, struct ddr_bw_info *ddr_bw_ch1) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed1 { u32 status; } tx_buf; @@ -555,7 +779,7 @@ EXPORT_SYMBOL_GPL(scpi_ddr_bandwidth_get); int scpi_ddr_get_clk_rate(void) { struct scpi_data_buf sdata; - struct rockchip_mbox_msg mdata; + struct rk3368_mbox_msg mdata; struct __packed1 { u32 status; } tx_buf; @@ -574,8 +798,56 @@ int scpi_ddr_get_clk_rate(void) } EXPORT_SYMBOL_GPL(scpi_ddr_get_clk_rate); +int scpi_thermal_get_temperature(void) +{ + int ret; + struct scpi_data_buf sdata; + struct rk3368_mbox_msg mdata; + struct __packed1 { + u32 status; + } tx_buf; + + struct __packed2 { + u32 status; + u32 tsadc_data; + } rx_buf; + + tx_buf.status = 0; + SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_THERMAL, + SCPI_THERMAL_GET_TSADC_DATA, tx_buf, rx_buf); + + ret = scpi_execute_cmd(&sdata); + if (ret) { + pr_err("get temperature from MCU failed, ret=%d\n", ret); + return ret; + } + + return rx_buf.tsadc_data; +} +EXPORT_SYMBOL_GPL(scpi_thermal_get_temperature); + +int scpi_thermal_set_clk_cycle(u32 cycle) +{ + struct scpi_data_buf sdata; + struct rk3368_mbox_msg mdata; + struct __packed1 { + u32 clk_cycle; + } tx_buf; + + struct __packed2 { + u32 status; + } rx_buf; + + tx_buf.clk_cycle = cycle; + SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_THERMAL, + SCPI_THERMAL_SET_TSADC_CYCLE, tx_buf, rx_buf); + + return scpi_execute_cmd(&sdata); +} +EXPORT_SYMBOL_GPL(scpi_thermal_set_clk_cycle); + static struct of_device_id mobx_scpi_of_match[] = { - { .compatible = "rockchip,mbox-scpi"}, + { .compatible = "rockchip,rk3368-scpi-legacy"}, { }, }; MODULE_DEVICE_TABLE(of, mobx_scpi_of_match); @@ -584,25 +856,44 @@ static int mobx_scpi_probe(struct platform_device *pdev) { int ret = 0; int retry = 3; - u32 ver = 0; - int check_version = 0; /*0: not check version, 1: check version*/ + int val = 0; + struct scpi_mcu_ver mcu_ver; + int check_version = 1; /*0: not check version, 1: check version*/ the_scpi_device = &pdev->dev; + /* try to get mboxes chan nums from DT */ + if (of_property_read_u32((&pdev->dev)->of_node, "chan-nums", &val)) { + dev_err(&pdev->dev, "parse mboxes chan-nums failed\n"); + ret = -EINVAL; + goto exit; + } + + max_chan_num = val; + + /* try to check up with SCPI version from MCU */ while ((retry--) && (check_version != 0)) { - ret = scpi_get_version(SCPI_VERSION, &ver); - if ((ret == 0) && (ver == SCPI_VERSION)) + memset(&mcu_ver, 0, sizeof(mcu_ver)); + + ret = scpi_get_version(SCPI_VERSION, &mcu_ver); + if ((ret == 0) && (mcu_ver.scpi_ver == SCPI_VERSION)) break; } if ((retry <= 0) && (check_version != 0)) { - dev_err(&pdev->dev, "Failed to get scpi version\n"); + dev_err(&pdev->dev, + "Scpi verison not match:kernel ver:0x%x, MCU ver:0x%x, ret=%d\n", + SCPI_VERSION, mcu_ver.scpi_ver, ret); ret = -EIO; goto exit; } - dev_info(&pdev->dev, - "Scpi initialize, version: 0x%x\n", ver); + dev_info(&pdev->dev, "Scpi initialize, version: 0x%x, chan nums: %d\n", + SCPI_VERSION, val); + + if (check_version) + dev_info(&pdev->dev, "MCU version: %s\n", mcu_ver.mcu_ver); + return 0; exit: the_scpi_device = NULL;