aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>2021-11-26 19:58:00 +0530
committerManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>2022-02-26 12:07:23 +0530
commit4e1adfd0a5326620b011a64c540623102b189eff (patch)
tree5b4376c2a6d041342b0247e4df69a6af11656c5c
parent8a137a3f149845f9f412c0abfdc77dbeffe42d39 (diff)
bus: mhi: ep: Add support for creating and destroying MHI EP devices
This commit adds support for creating and destroying MHI endpoint devices. The MHI endpoint devices binds to the MHI endpoint channels and are used to transfer data between MHI host and endpoint device. There is a single MHI EP device for each channel pair. The devices will be created when the corresponding channels has been started by the host and will be destroyed during MHI EP power down and reset. Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
-rw-r--r--drivers/bus/mhi/ep/main.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
index 2bdcf1657479..3afae0bfd83c 100644
--- a/drivers/bus/mhi/ep/main.c
+++ b/drivers/bus/mhi/ep/main.c
@@ -68,6 +68,89 @@ static struct mhi_ep_device *mhi_ep_alloc_device(struct mhi_ep_cntrl *mhi_cntrl,
return mhi_dev;
}
+/*
+ * MHI channels are always defined in pairs with UL as the even numbered
+ * channel and DL as odd numbered one. This function gets UL channel (primary)
+ * as the ch_id and always looks after the next entry in channel list for
+ * the corresponding DL channel (secondary).
+ */
+static int mhi_ep_create_device(struct mhi_ep_cntrl *mhi_cntrl, u32 ch_id)
+{
+ struct mhi_ep_chan *mhi_chan = &mhi_cntrl->mhi_chan[ch_id];
+ struct device *dev = mhi_cntrl->cntrl_dev;
+ struct mhi_ep_device *mhi_dev;
+ int ret;
+
+ /* Check if the channel name is same for both UL and DL */
+ if (strcmp(mhi_chan->name, mhi_chan[1].name)) {
+ dev_err(dev, "UL and DL channel names are not same: (%s) != (%s)\n",
+ mhi_chan->name, mhi_chan[1].name);
+ return -EINVAL;
+ }
+
+ mhi_dev = mhi_ep_alloc_device(mhi_cntrl, MHI_DEVICE_XFER);
+ if (IS_ERR(mhi_dev))
+ return PTR_ERR(mhi_dev);
+
+ /* Configure primary channel */
+ mhi_dev->ul_chan = mhi_chan;
+ get_device(&mhi_dev->dev);
+ mhi_chan->mhi_dev = mhi_dev;
+
+ /* Configure secondary channel as well */
+ mhi_chan++;
+ mhi_dev->dl_chan = mhi_chan;
+ get_device(&mhi_dev->dev);
+ mhi_chan->mhi_dev = mhi_dev;
+
+ /* Channel name is same for both UL and DL */
+ mhi_dev->name = mhi_chan->name;
+ dev_set_name(&mhi_dev->dev, "%s_%s",
+ dev_name(&mhi_cntrl->mhi_dev->dev),
+ mhi_dev->name);
+
+ ret = device_add(&mhi_dev->dev);
+ if (ret)
+ put_device(&mhi_dev->dev);
+
+ return ret;
+}
+
+static int mhi_ep_destroy_device(struct device *dev, void *data)
+{
+ struct mhi_ep_device *mhi_dev;
+ struct mhi_ep_cntrl *mhi_cntrl;
+ struct mhi_ep_chan *ul_chan, *dl_chan;
+
+ if (dev->bus != &mhi_ep_bus_type)
+ return 0;
+
+ mhi_dev = to_mhi_ep_device(dev);
+ mhi_cntrl = mhi_dev->mhi_cntrl;
+
+ /* Only destroy devices created for channels */
+ if (mhi_dev->dev_type == MHI_DEVICE_CONTROLLER)
+ return 0;
+
+ ul_chan = mhi_dev->ul_chan;
+ dl_chan = mhi_dev->dl_chan;
+
+ if (ul_chan)
+ put_device(&ul_chan->mhi_dev->dev);
+
+ if (dl_chan)
+ put_device(&dl_chan->mhi_dev->dev);
+
+ dev_dbg(&mhi_cntrl->mhi_dev->dev, "Destroying device for chan:%s\n",
+ mhi_dev->name);
+
+ /* Notify the client and remove the device from MHI bus */
+ device_del(dev);
+ put_device(dev);
+
+ return 0;
+}
+
static int mhi_ep_chan_init(struct mhi_ep_cntrl *mhi_cntrl,
const struct mhi_ep_cntrl_config *config)
{