162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2011-2017, The Linux Foundation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/slab.h> 762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 862306a36Sopenharmony_ci#include "slimbus.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/** 1162306a36Sopenharmony_ci * slim_msg_response() - Deliver Message response received from a device to the 1262306a36Sopenharmony_ci * framework. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * @ctrl: Controller handle 1562306a36Sopenharmony_ci * @reply: Reply received from the device 1662306a36Sopenharmony_ci * @len: Length of the reply 1762306a36Sopenharmony_ci * @tid: Transaction ID received with which framework can associate reply. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Called by controller to inform framework about the response received. 2062306a36Sopenharmony_ci * This helps in making the API asynchronous, and controller-driver doesn't need 2162306a36Sopenharmony_ci * to manage 1 more table other than the one managed by framework mapping TID 2262306a36Sopenharmony_ci * with buffers 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_civoid slim_msg_response(struct slim_controller *ctrl, u8 *reply, u8 tid, u8 len) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct slim_msg_txn *txn; 2762306a36Sopenharmony_ci struct slim_val_inf *msg; 2862306a36Sopenharmony_ci unsigned long flags; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci spin_lock_irqsave(&ctrl->txn_lock, flags); 3162306a36Sopenharmony_ci txn = idr_find(&ctrl->tid_idr, tid); 3262306a36Sopenharmony_ci spin_unlock_irqrestore(&ctrl->txn_lock, flags); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (txn == NULL) 3562306a36Sopenharmony_ci return; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci msg = txn->msg; 3862306a36Sopenharmony_ci if (msg == NULL || msg->rbuf == NULL) { 3962306a36Sopenharmony_ci dev_err(ctrl->dev, "Got response to invalid TID:%d, len:%d\n", 4062306a36Sopenharmony_ci tid, len); 4162306a36Sopenharmony_ci return; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci slim_free_txn_tid(ctrl, txn); 4562306a36Sopenharmony_ci memcpy(msg->rbuf, reply, len); 4662306a36Sopenharmony_ci if (txn->comp) 4762306a36Sopenharmony_ci complete(txn->comp); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* Remove runtime-pm vote now that response was received for TID txn */ 5062306a36Sopenharmony_ci pm_runtime_mark_last_busy(ctrl->dev); 5162306a36Sopenharmony_ci pm_runtime_put_autosuspend(ctrl->dev); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(slim_msg_response); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/** 5662306a36Sopenharmony_ci * slim_alloc_txn_tid() - Allocate a tid to txn 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * @ctrl: Controller handle 5962306a36Sopenharmony_ci * @txn: transaction to be allocated with tid. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * Return: zero on success with valid txn->tid and error code on failures. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ciint slim_alloc_txn_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci unsigned long flags; 6662306a36Sopenharmony_ci int ret = 0; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci spin_lock_irqsave(&ctrl->txn_lock, flags); 6962306a36Sopenharmony_ci ret = idr_alloc_cyclic(&ctrl->tid_idr, txn, 1, 7062306a36Sopenharmony_ci SLIM_MAX_TIDS, GFP_ATOMIC); 7162306a36Sopenharmony_ci if (ret < 0) { 7262306a36Sopenharmony_ci spin_unlock_irqrestore(&ctrl->txn_lock, flags); 7362306a36Sopenharmony_ci return ret; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci txn->tid = ret; 7662306a36Sopenharmony_ci spin_unlock_irqrestore(&ctrl->txn_lock, flags); 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(slim_alloc_txn_tid); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/** 8262306a36Sopenharmony_ci * slim_free_txn_tid() - Free tid of txn 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * @ctrl: Controller handle 8562306a36Sopenharmony_ci * @txn: transaction whose tid should be freed 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_civoid slim_free_txn_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci unsigned long flags; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci spin_lock_irqsave(&ctrl->txn_lock, flags); 9262306a36Sopenharmony_ci idr_remove(&ctrl->tid_idr, txn->tid); 9362306a36Sopenharmony_ci spin_unlock_irqrestore(&ctrl->txn_lock, flags); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(slim_free_txn_tid); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/** 9862306a36Sopenharmony_ci * slim_do_transfer() - Process a SLIMbus-messaging transaction 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci * @ctrl: Controller handle 10162306a36Sopenharmony_ci * @txn: Transaction to be sent over SLIMbus 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * Called by controller to transmit messaging transactions not dealing with 10462306a36Sopenharmony_ci * Interface/Value elements. (e.g. transmitting a message to assign logical 10562306a36Sopenharmony_ci * address to a slave device 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * Return: -ETIMEDOUT: If transmission of this message timed out 10862306a36Sopenharmony_ci * (e.g. due to bus lines not being clocked or driven by controller) 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ciint slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(done); 11362306a36Sopenharmony_ci bool need_tid = false, clk_pause_msg = false; 11462306a36Sopenharmony_ci int ret, timeout; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* 11762306a36Sopenharmony_ci * do not vote for runtime-PM if the transactions are part of clock 11862306a36Sopenharmony_ci * pause sequence 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci if (ctrl->sched.clk_state == SLIM_CLK_ENTERING_PAUSE && 12162306a36Sopenharmony_ci (txn->mt == SLIM_MSG_MT_CORE && 12262306a36Sopenharmony_ci txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION && 12362306a36Sopenharmony_ci txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW)) 12462306a36Sopenharmony_ci clk_pause_msg = true; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (!clk_pause_msg) { 12762306a36Sopenharmony_ci ret = pm_runtime_get_sync(ctrl->dev); 12862306a36Sopenharmony_ci if (ctrl->sched.clk_state != SLIM_CLK_ACTIVE) { 12962306a36Sopenharmony_ci dev_err(ctrl->dev, "ctrl wrong state:%d, ret:%d\n", 13062306a36Sopenharmony_ci ctrl->sched.clk_state, ret); 13162306a36Sopenharmony_ci goto slim_xfer_err; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci /* Initialize tid to invalid value */ 13562306a36Sopenharmony_ci txn->tid = 0; 13662306a36Sopenharmony_ci need_tid = slim_tid_txn(txn->mt, txn->mc); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (need_tid) { 13962306a36Sopenharmony_ci ret = slim_alloc_txn_tid(ctrl, txn); 14062306a36Sopenharmony_ci if (ret) 14162306a36Sopenharmony_ci return ret; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!txn->msg->comp) 14462306a36Sopenharmony_ci txn->comp = &done; 14562306a36Sopenharmony_ci else 14662306a36Sopenharmony_ci txn->comp = txn->comp; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci ret = ctrl->xfer_msg(ctrl, txn); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (!ret && need_tid && !txn->msg->comp) { 15262306a36Sopenharmony_ci unsigned long ms = txn->rl + HZ; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci timeout = wait_for_completion_timeout(txn->comp, 15562306a36Sopenharmony_ci msecs_to_jiffies(ms)); 15662306a36Sopenharmony_ci if (!timeout) { 15762306a36Sopenharmony_ci ret = -ETIMEDOUT; 15862306a36Sopenharmony_ci slim_free_txn_tid(ctrl, txn); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (ret) 16362306a36Sopenharmony_ci dev_err(ctrl->dev, "Tx:MT:0x%x, MC:0x%x, LA:0x%x failed:%d\n", 16462306a36Sopenharmony_ci txn->mt, txn->mc, txn->la, ret); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cislim_xfer_err: 16762306a36Sopenharmony_ci if (!clk_pause_msg && (txn->tid == 0 || ret == -ETIMEDOUT)) { 16862306a36Sopenharmony_ci /* 16962306a36Sopenharmony_ci * remove runtime-pm vote if this was TX only, or 17062306a36Sopenharmony_ci * if there was error during this transaction 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci pm_runtime_mark_last_busy(ctrl->dev); 17362306a36Sopenharmony_ci pm_runtime_put_autosuspend(ctrl->dev); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci return ret; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(slim_do_transfer); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int slim_val_inf_sanity(struct slim_controller *ctrl, 18062306a36Sopenharmony_ci struct slim_val_inf *msg, u8 mc) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci if (!msg || msg->num_bytes > 16 || 18362306a36Sopenharmony_ci (msg->start_offset + msg->num_bytes) > 0xC00) 18462306a36Sopenharmony_ci goto reterr; 18562306a36Sopenharmony_ci switch (mc) { 18662306a36Sopenharmony_ci case SLIM_MSG_MC_REQUEST_VALUE: 18762306a36Sopenharmony_ci case SLIM_MSG_MC_REQUEST_INFORMATION: 18862306a36Sopenharmony_ci if (msg->rbuf != NULL) 18962306a36Sopenharmony_ci return 0; 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci case SLIM_MSG_MC_CHANGE_VALUE: 19362306a36Sopenharmony_ci case SLIM_MSG_MC_CLEAR_INFORMATION: 19462306a36Sopenharmony_ci if (msg->wbuf != NULL) 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci case SLIM_MSG_MC_REQUEST_CHANGE_VALUE: 19962306a36Sopenharmony_ci case SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION: 20062306a36Sopenharmony_ci if (msg->rbuf != NULL && msg->wbuf != NULL) 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_cireterr: 20562306a36Sopenharmony_ci if (msg) 20662306a36Sopenharmony_ci dev_err(ctrl->dev, "Sanity check failed:msg:offset:0x%x, mc:%d\n", 20762306a36Sopenharmony_ci msg->start_offset, mc); 20862306a36Sopenharmony_ci return -EINVAL; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic u16 slim_slicesize(int code) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci static const u8 sizetocode[16] = { 21462306a36Sopenharmony_ci 0, 1, 2, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7 21562306a36Sopenharmony_ci }; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci code = clamp(code, 1, (int)ARRAY_SIZE(sizetocode)); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return sizetocode[code - 1]; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/** 22362306a36Sopenharmony_ci * slim_xfer_msg() - Transfer a value info message on slim device 22462306a36Sopenharmony_ci * 22562306a36Sopenharmony_ci * @sbdev: slim device to which this msg has to be transfered 22662306a36Sopenharmony_ci * @msg: value info message pointer 22762306a36Sopenharmony_ci * @mc: message code of the message 22862306a36Sopenharmony_ci * 22962306a36Sopenharmony_ci * Called by drivers which want to transfer a vlaue or info elements. 23062306a36Sopenharmony_ci * 23162306a36Sopenharmony_ci * Return: -ETIMEDOUT: If transmission of this message timed out 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ciint slim_xfer_msg(struct slim_device *sbdev, struct slim_val_inf *msg, 23462306a36Sopenharmony_ci u8 mc) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci DEFINE_SLIM_LDEST_TXN(txn_stack, mc, 6, sbdev->laddr, msg); 23762306a36Sopenharmony_ci struct slim_msg_txn *txn = &txn_stack; 23862306a36Sopenharmony_ci struct slim_controller *ctrl = sbdev->ctrl; 23962306a36Sopenharmony_ci int ret; 24062306a36Sopenharmony_ci u16 sl; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (!ctrl) 24362306a36Sopenharmony_ci return -EINVAL; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci ret = slim_val_inf_sanity(ctrl, msg, mc); 24662306a36Sopenharmony_ci if (ret) 24762306a36Sopenharmony_ci return ret; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci sl = slim_slicesize(msg->num_bytes); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci dev_dbg(ctrl->dev, "SB xfer msg:os:%x, len:%d, MC:%x, sl:%x\n", 25262306a36Sopenharmony_ci msg->start_offset, msg->num_bytes, mc, sl); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci txn->ec = ((sl | (1 << 3)) | ((msg->start_offset & 0xFFF) << 4)); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci switch (mc) { 25762306a36Sopenharmony_ci case SLIM_MSG_MC_REQUEST_CHANGE_VALUE: 25862306a36Sopenharmony_ci case SLIM_MSG_MC_CHANGE_VALUE: 25962306a36Sopenharmony_ci case SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION: 26062306a36Sopenharmony_ci case SLIM_MSG_MC_CLEAR_INFORMATION: 26162306a36Sopenharmony_ci txn->rl += msg->num_bytes; 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci default: 26462306a36Sopenharmony_ci break; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (slim_tid_txn(txn->mt, txn->mc)) 26862306a36Sopenharmony_ci txn->rl++; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return slim_do_transfer(ctrl, txn); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(slim_xfer_msg); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void slim_fill_msg(struct slim_val_inf *msg, u32 addr, 27562306a36Sopenharmony_ci size_t count, u8 *rbuf, u8 *wbuf) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci msg->start_offset = addr; 27862306a36Sopenharmony_ci msg->num_bytes = count; 27962306a36Sopenharmony_ci msg->rbuf = rbuf; 28062306a36Sopenharmony_ci msg->wbuf = wbuf; 28162306a36Sopenharmony_ci msg->comp = NULL; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * slim_read() - Read SLIMbus value element 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * @sdev: client handle. 28862306a36Sopenharmony_ci * @addr: address of value element to read. 28962306a36Sopenharmony_ci * @count: number of bytes to read. Maximum bytes allowed are 16. 29062306a36Sopenharmony_ci * @val: will return what the value element value was 29162306a36Sopenharmony_ci * 29262306a36Sopenharmony_ci * Return: -EINVAL for Invalid parameters, -ETIMEDOUT If transmission of 29362306a36Sopenharmony_ci * this message timed out (e.g. due to bus lines not being clocked 29462306a36Sopenharmony_ci * or driven by controller) 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ciint slim_read(struct slim_device *sdev, u32 addr, size_t count, u8 *val) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct slim_val_inf msg; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci slim_fill_msg(&msg, addr, count, val, NULL); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return slim_xfer_msg(sdev, &msg, SLIM_MSG_MC_REQUEST_VALUE); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(slim_read); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/** 30762306a36Sopenharmony_ci * slim_readb() - Read byte from SLIMbus value element 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * @sdev: client handle. 31062306a36Sopenharmony_ci * @addr: address in the value element to read. 31162306a36Sopenharmony_ci * 31262306a36Sopenharmony_ci * Return: byte value of value element. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ciint slim_readb(struct slim_device *sdev, u32 addr) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci int ret; 31762306a36Sopenharmony_ci u8 buf; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci ret = slim_read(sdev, addr, 1, &buf); 32062306a36Sopenharmony_ci if (ret < 0) 32162306a36Sopenharmony_ci return ret; 32262306a36Sopenharmony_ci else 32362306a36Sopenharmony_ci return buf; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(slim_readb); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/** 32862306a36Sopenharmony_ci * slim_write() - Write SLIMbus value element 32962306a36Sopenharmony_ci * 33062306a36Sopenharmony_ci * @sdev: client handle. 33162306a36Sopenharmony_ci * @addr: address in the value element to write. 33262306a36Sopenharmony_ci * @count: number of bytes to write. Maximum bytes allowed are 16. 33362306a36Sopenharmony_ci * @val: value to write to value element 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * Return: -EINVAL for Invalid parameters, -ETIMEDOUT If transmission of 33662306a36Sopenharmony_ci * this message timed out (e.g. due to bus lines not being clocked 33762306a36Sopenharmony_ci * or driven by controller) 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_ciint slim_write(struct slim_device *sdev, u32 addr, size_t count, u8 *val) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct slim_val_inf msg; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci slim_fill_msg(&msg, addr, count, NULL, val); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return slim_xfer_msg(sdev, &msg, SLIM_MSG_MC_CHANGE_VALUE); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(slim_write); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/** 35062306a36Sopenharmony_ci * slim_writeb() - Write byte to SLIMbus value element 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * @sdev: client handle. 35362306a36Sopenharmony_ci * @addr: address of value element to write. 35462306a36Sopenharmony_ci * @value: value to write to value element 35562306a36Sopenharmony_ci * 35662306a36Sopenharmony_ci * Return: -EINVAL for Invalid parameters, -ETIMEDOUT If transmission of 35762306a36Sopenharmony_ci * this message timed out (e.g. due to bus lines not being clocked 35862306a36Sopenharmony_ci * or driven by controller) 35962306a36Sopenharmony_ci * 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ciint slim_writeb(struct slim_device *sdev, u32 addr, u8 value) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci return slim_write(sdev, addr, 1, &value); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(slim_writeb); 366