mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 12:25:00 -04:00
Merge "dma: gpi: Add support to assign static GPII for I2C Touch on Lahaina"
This commit is contained in:
commit
955e4e41e9
3 changed files with 503 additions and 204 deletions
|
|
@ -134,6 +134,11 @@ enum EV_PRIORITY {
|
|||
#define STATE_IGNORE (U32_MAX)
|
||||
#define REQ_OF_DMA_ARGS (5) /* # of arguments required from client */
|
||||
|
||||
#define NOOP_TRE_MASK(link_rx, bei, ieot, ieob, ch) \
|
||||
((0x0 << 20) | (0x0 << 16) | (link_rx << 11) | (bei << 10) | \
|
||||
(ieot << 9) | (ieob << 8) | ch)
|
||||
#define NOOP_TRE (0x0 << 20 | 0x1 << 16)
|
||||
|
||||
struct __packed gpi_error_log_entry {
|
||||
u32 routine : 4;
|
||||
u32 type : 4;
|
||||
|
|
@ -436,6 +441,7 @@ struct gpi_dev {
|
|||
void *ee_base; /*ee register base address*/
|
||||
u32 max_gpii; /* maximum # of gpii instances available per gpi block */
|
||||
u32 gpii_mask; /* gpii instances available for apps */
|
||||
u32 static_gpii_mask; /* gpii instances assigned statically */
|
||||
u32 ev_factor; /* ev ring length factor */
|
||||
u32 smmu_cfg;
|
||||
dma_addr_t iova_base;
|
||||
|
|
@ -445,6 +451,7 @@ struct gpi_dev {
|
|||
u32 ipc_log_lvl;
|
||||
u32 klog_lvl;
|
||||
struct dentry *dentry;
|
||||
bool is_le_vm;
|
||||
};
|
||||
|
||||
static struct gpi_dev *gpi_dev_dbg[5];
|
||||
|
|
@ -544,6 +551,8 @@ struct gpii_chan {
|
|||
u32 dir;
|
||||
struct gpi_ring ch_ring;
|
||||
struct gpi_client_info client_info;
|
||||
u32 lock_tre_set;
|
||||
u32 num_tre;
|
||||
};
|
||||
|
||||
struct gpii {
|
||||
|
|
@ -1663,7 +1672,8 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan,
|
|||
return;
|
||||
}
|
||||
} else if (compl_event->code == MSM_GPI_TCE_EOB) {
|
||||
goto gpi_free_desc;
|
||||
if (!(gpii_chan->num_tre == 1 && gpii_chan->lock_tre_set))
|
||||
goto gpi_free_desc;
|
||||
}
|
||||
|
||||
tx_cb_param = vd->tx.callback_param;
|
||||
|
|
@ -2199,6 +2209,7 @@ int gpi_terminate_all(struct dma_chan *chan)
|
|||
{
|
||||
struct gpii_chan *gpii_chan = to_gpii_chan(chan);
|
||||
struct gpii *gpii = gpii_chan->gpii;
|
||||
struct gpi_dev *gpi_dev = gpii->gpi_dev;
|
||||
int schid, echid, i;
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -2213,21 +2224,22 @@ int gpi_terminate_all(struct dma_chan *chan)
|
|||
echid = (gpii->protocol == SE_PROTOCOL_UART) ? schid + 1 :
|
||||
MAX_CHANNELS_PER_GPII;
|
||||
|
||||
/* stop the channel */
|
||||
for (i = schid; i < echid; i++) {
|
||||
gpii_chan = &gpii->gpii_chan[i];
|
||||
if (!gpi_dev->is_le_vm) {
|
||||
/* stop the channel */
|
||||
for (i = schid; i < echid; i++) {
|
||||
gpii_chan = &gpii->gpii_chan[i];
|
||||
|
||||
/* disable ch state so no more TRE processing */
|
||||
write_lock_irq(&gpii->pm_lock);
|
||||
gpii_chan->pm_state = PREPARE_TERMINATE;
|
||||
write_unlock_irq(&gpii->pm_lock);
|
||||
/* disable ch state so no more TRE processing */
|
||||
write_lock_irq(&gpii->pm_lock);
|
||||
gpii_chan->pm_state = PREPARE_TERMINATE;
|
||||
write_unlock_irq(&gpii->pm_lock);
|
||||
|
||||
/* send command to Stop the channel */
|
||||
ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_STOP);
|
||||
if (ret)
|
||||
GPII_ERR(gpii, gpii_chan->chid,
|
||||
"Error Stopping Channel:%d resetting anyway\n",
|
||||
ret);
|
||||
/* send command to Stop the channel */
|
||||
ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_STOP);
|
||||
if (ret)
|
||||
GPII_ERR(gpii, gpii_chan->chid,
|
||||
"Error Stopping Chan:%d resetting\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
/* reset the channels (clears any pending tre) */
|
||||
|
|
@ -2267,6 +2279,44 @@ terminate_exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void gpi_noop_tre(struct gpii_chan *gpii_chan)
|
||||
{
|
||||
struct gpii *gpii = gpii_chan->gpii;
|
||||
struct gpi_ring *ch_ring = &gpii_chan->ch_ring;
|
||||
phys_addr_t local_rp, local_wp;
|
||||
void *cntxt_rp;
|
||||
u32 noop_mask, noop_tre;
|
||||
struct msm_gpi_tre *tre;
|
||||
|
||||
GPII_INFO(gpii, gpii_chan->chid, "Enter\n");
|
||||
|
||||
local_rp = to_physical(ch_ring, ch_ring->rp);
|
||||
local_wp = to_physical(ch_ring, ch_ring->wp);
|
||||
cntxt_rp = ch_ring->rp;
|
||||
|
||||
GPII_INFO(gpii, gpii_chan->chid,
|
||||
"local_rp:0x%0llx local_wp:0x%0llx\n", local_rp, local_wp);
|
||||
|
||||
noop_mask = NOOP_TRE_MASK(1, 0, 0, 0, 1);
|
||||
noop_tre = NOOP_TRE;
|
||||
|
||||
while (local_rp != local_wp) {
|
||||
tre = (struct msm_gpi_tre *)cntxt_rp;
|
||||
tre->dword[3] &= noop_mask;
|
||||
tre->dword[3] |= noop_tre;
|
||||
local_rp += ch_ring->el_size;
|
||||
cntxt_rp += ch_ring->el_size;
|
||||
if (cntxt_rp >= (ch_ring->base + ch_ring->len)) {
|
||||
cntxt_rp = ch_ring->base;
|
||||
local_rp = to_physical(ch_ring, ch_ring->base);
|
||||
}
|
||||
GPII_INFO(gpii, gpii_chan->chid,
|
||||
"local_rp:0x%0llx\n", local_rp);
|
||||
}
|
||||
|
||||
GPII_INFO(gpii, gpii_chan->chid, "exit\n");
|
||||
}
|
||||
|
||||
/* pause dma transfer for all channels */
|
||||
static int gpi_pause(struct dma_chan *chan)
|
||||
{
|
||||
|
|
@ -2277,38 +2327,41 @@ static int gpi_pause(struct dma_chan *chan)
|
|||
GPII_INFO(gpii, gpii_chan->chid, "Enter\n");
|
||||
mutex_lock(&gpii->ctrl_lock);
|
||||
|
||||
/*
|
||||
* pause/resume are per gpii not per channel, so
|
||||
* client needs to call pause only once
|
||||
*/
|
||||
if (gpii->pm_state == PAUSE_STATE) {
|
||||
GPII_INFO(gpii, gpii_chan->chid,
|
||||
"channel is already paused\n");
|
||||
mutex_unlock(&gpii->ctrl_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* send stop command to stop the channels */
|
||||
for (i = 0; i < MAX_CHANNELS_PER_GPII; i++) {
|
||||
ret = gpi_send_cmd(gpii, &gpii->gpii_chan[i], GPI_CH_CMD_STOP);
|
||||
gpii_chan = &gpii->gpii_chan[i];
|
||||
/* disable ch state so no more TRE processing */
|
||||
write_lock_irq(&gpii->pm_lock);
|
||||
gpii_chan->pm_state = PREPARE_TERMINATE;
|
||||
write_unlock_irq(&gpii->pm_lock);
|
||||
/* send command to Stop the channel */
|
||||
ret = gpi_send_cmd(gpii, gpii_chan, GPI_CH_CMD_STOP);
|
||||
if (ret) {
|
||||
GPII_ERR(gpii, gpii->gpii_chan[i].chid,
|
||||
"Error stopping chan, ret:%d\n", ret);
|
||||
mutex_unlock(&gpii->ctrl_lock);
|
||||
return -ECONNRESET;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CHANNELS_PER_GPII; i++) {
|
||||
gpii_chan = &gpii->gpii_chan[i];
|
||||
gpi_noop_tre(gpii_chan);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CHANNELS_PER_GPII; i++) {
|
||||
gpii_chan = &gpii->gpii_chan[i];
|
||||
|
||||
ret = gpi_start_chan(gpii_chan);
|
||||
if (ret) {
|
||||
GPII_ERR(gpii, gpii_chan->chid,
|
||||
"Error Starting Channel ret:%d\n", ret);
|
||||
mutex_unlock(&gpii->ctrl_lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
disable_irq(gpii->irq);
|
||||
|
||||
/* Wait for threads to complete out */
|
||||
tasklet_kill(&gpii->ev_task);
|
||||
|
||||
write_lock_irq(&gpii->pm_lock);
|
||||
gpii->pm_state = PAUSE_STATE;
|
||||
write_unlock_irq(&gpii->pm_lock);
|
||||
mutex_unlock(&gpii->ctrl_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2378,6 +2431,7 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan,
|
|||
const gfp_t gfp = GFP_ATOMIC;
|
||||
struct gpi_desc *gpi_desc;
|
||||
u32 tre_type;
|
||||
gpii_chan->num_tre = sg_len;
|
||||
|
||||
GPII_VERB(gpii, gpii_chan->chid, "enter\n");
|
||||
|
||||
|
|
@ -2414,6 +2468,12 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan,
|
|||
for_each_sg(sgl, sg, sg_len, i) {
|
||||
tre = sg_virt(sg);
|
||||
|
||||
if (sg_len == 1) {
|
||||
tre_type =
|
||||
MSM_GPI_TRE_TYPE(((struct msm_gpi_tre *)tre));
|
||||
gpii_chan->lock_tre_set =
|
||||
tre_type == MSM_GPI_TRE_LOCK ? true : false;
|
||||
}
|
||||
/* Check if last tre is an unlock tre */
|
||||
if (i == sg_len - 1) {
|
||||
tre_type =
|
||||
|
|
@ -2718,14 +2778,17 @@ xfer_alloc_err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int gpi_find_avail_gpii(struct gpi_dev *gpi_dev, u32 seid)
|
||||
static int gpi_find_avail_gpii(struct gpi_dev *gpi_dev, u32 seid,
|
||||
bool static_gpii)
|
||||
{
|
||||
int gpii;
|
||||
struct gpii_chan *tx_chan, *rx_chan;
|
||||
u32 gpii_mask =
|
||||
static_gpii ? gpi_dev->static_gpii_mask : gpi_dev->gpii_mask;
|
||||
|
||||
/* check if same seid is already configured for another chid */
|
||||
for (gpii = 0; gpii < gpi_dev->max_gpii; gpii++) {
|
||||
if (!((1 << gpii) & gpi_dev->gpii_mask))
|
||||
if (!((1 << gpii) & gpii_mask))
|
||||
continue;
|
||||
|
||||
tx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_TX_CHAN];
|
||||
|
|
@ -2739,7 +2802,7 @@ static int gpi_find_avail_gpii(struct gpi_dev *gpi_dev, u32 seid)
|
|||
|
||||
/* no channels configured with same seid, return next avail gpii */
|
||||
for (gpii = 0; gpii < gpi_dev->max_gpii; gpii++) {
|
||||
if (!((1 << gpii) & gpi_dev->gpii_mask))
|
||||
if (!((1 << gpii) & gpii_mask))
|
||||
continue;
|
||||
|
||||
tx_chan = &gpi_dev->gpiis[gpii].gpii_chan[GPI_TX_CHAN];
|
||||
|
|
@ -2764,8 +2827,9 @@ static struct dma_chan *gpi_of_dma_xlate(struct of_phandle_args *args,
|
|||
{
|
||||
struct gpi_dev *gpi_dev = (struct gpi_dev *)of_dma->of_dma_data;
|
||||
u32 seid, chid;
|
||||
int gpii;
|
||||
int gpii, val;
|
||||
struct gpii_chan *gpii_chan;
|
||||
bool static_gpii;
|
||||
|
||||
if (args->args_count < REQ_OF_DMA_ARGS) {
|
||||
GPI_ERR(gpi_dev,
|
||||
|
|
@ -2781,9 +2845,11 @@ static struct dma_chan *gpi_of_dma_xlate(struct of_phandle_args *args,
|
|||
}
|
||||
|
||||
seid = args->args[1];
|
||||
val = (args->args[4] & STATIC_GPII_BMSK) >> STATIC_GPII_SHFT;
|
||||
static_gpii = (val == 1) ? true : false;
|
||||
|
||||
/* find next available gpii to use */
|
||||
gpii = gpi_find_avail_gpii(gpi_dev, seid);
|
||||
gpii = gpi_find_avail_gpii(gpi_dev, seid, static_gpii);
|
||||
if (gpii < 0) {
|
||||
GPI_ERR(gpi_dev, "no available gpii instances\n");
|
||||
return NULL;
|
||||
|
|
@ -2800,7 +2866,7 @@ static struct dma_chan *gpi_of_dma_xlate(struct of_phandle_args *args,
|
|||
gpii_chan->seid = seid;
|
||||
gpii_chan->protocol = args->args[2];
|
||||
gpii_chan->req_tres = args->args[3];
|
||||
gpii_chan->priority = args->args[4];
|
||||
gpii_chan->priority = args->args[4] & GPI_EV_PRIORITY_BMSK;
|
||||
|
||||
GPI_LOG(gpi_dev,
|
||||
"client req. gpii:%u chid:%u #_tre:%u priority:%u protocol:%u\n",
|
||||
|
|
@ -2838,7 +2904,8 @@ static void gpi_setup_debug(struct gpi_dev *gpi_dev)
|
|||
for (i = 0; i < gpi_dev->max_gpii; i++) {
|
||||
struct gpii *gpii;
|
||||
|
||||
if (!((1 << i) & gpi_dev->gpii_mask))
|
||||
if (!(((1 << i) & gpi_dev->gpii_mask) ||
|
||||
((1 << i) & gpi_dev->static_gpii_mask)))
|
||||
continue;
|
||||
|
||||
gpii = &gpi_dev->gpiis[i];
|
||||
|
|
@ -2910,6 +2977,11 @@ static int gpi_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(gpi_dev->dev->of_node,
|
||||
"qcom,static-gpii-mask", &gpi_dev->static_gpii_mask);
|
||||
if (!ret)
|
||||
GPI_LOG(gpi_dev, "static GPII usecase\n");
|
||||
|
||||
ret = of_property_read_u32(gpi_dev->dev->of_node,
|
||||
"qcom,gpi-ee-offset", &gpi_ee_offset);
|
||||
if (ret)
|
||||
|
|
@ -2941,13 +3013,19 @@ static int gpi_probe(struct platform_device *pdev)
|
|||
if (!gpi_dev->gpiis)
|
||||
return -ENOMEM;
|
||||
|
||||
gpi_dev->is_le_vm = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,le-vm");
|
||||
if (gpi_dev->is_le_vm)
|
||||
GPI_LOG(gpi_dev, "LE-VM usecase\n");
|
||||
|
||||
/* setup all the supported gpii */
|
||||
INIT_LIST_HEAD(&gpi_dev->dma_device.channels);
|
||||
for (i = 0; i < gpi_dev->max_gpii; i++) {
|
||||
struct gpii *gpii = &gpi_dev->gpiis[i];
|
||||
int chan;
|
||||
|
||||
if (!((1 << i) & gpi_dev->gpii_mask))
|
||||
if (!(((1 << i) & gpi_dev->gpii_mask) ||
|
||||
((1 << i) & gpi_dev->static_gpii_mask)))
|
||||
continue;
|
||||
|
||||
/* set up ev cntxt register map */
|
||||
|
|
@ -3075,7 +3153,8 @@ static int gpi_remove(struct platform_device *pdev)
|
|||
struct gpii *gpii = &gpi_dev->gpiis[i];
|
||||
int chan;
|
||||
|
||||
if (!((1 << i) & gpi_dev->gpii_mask))
|
||||
if (!(((1 << i) & gpi_dev->gpii_mask) ||
|
||||
((1 << i) & gpi_dev->static_gpii_mask)))
|
||||
continue;
|
||||
|
||||
for (chan = 0; chan < MAX_CHANNELS_PER_GPII; chan++) {
|
||||
|
|
|
|||
|
|
@ -128,6 +128,9 @@ struct geni_i2c_dev {
|
|||
u32 dbg_num;
|
||||
struct dbg_buf_ctxt *dbg_buf_ptr;
|
||||
bool is_le_vm;
|
||||
bool req_chan;
|
||||
bool first_resume;
|
||||
bool gpi_reset;
|
||||
};
|
||||
|
||||
static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE];
|
||||
|
|
@ -457,29 +460,16 @@ static void gi2c_gsi_rx_cb(void *ptr)
|
|||
}
|
||||
}
|
||||
|
||||
static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||
int num)
|
||||
static int geni_i2c_gsi_request_channel(struct geni_i2c_dev *gi2c)
|
||||
{
|
||||
struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
|
||||
int i, ret = 0, timeout = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!gi2c->tx_c) {
|
||||
gi2c->tx_c = dma_request_slave_channel(gi2c->dev, "tx");
|
||||
if (!gi2c->tx_c) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"tx dma req slv chan ret :%d\n", ret);
|
||||
ret = -EIO;
|
||||
goto geni_i2c_gsi_xfer_out;
|
||||
}
|
||||
gi2c->tx_ev.init.callback = gi2c_ev_cb;
|
||||
gi2c->tx_ev.init.cb_param = gi2c;
|
||||
gi2c->tx_ev.cmd = MSM_GPI_INIT;
|
||||
gi2c->tx_c->private = &gi2c->tx_ev;
|
||||
ret = dmaengine_slave_config(gi2c->tx_c, NULL);
|
||||
if (ret) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"tx dma slave config ret :%d\n", ret);
|
||||
goto geni_i2c_gsi_xfer_out;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -488,65 +478,320 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
if (!gi2c->rx_c) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"rx dma req slv chan ret :%d\n", ret);
|
||||
ret = -EIO;
|
||||
goto geni_i2c_gsi_xfer_out;
|
||||
dma_release_channel(gi2c->tx_c);
|
||||
return -EIO;
|
||||
}
|
||||
gi2c->rx_ev.init.cb_param = gi2c;
|
||||
gi2c->rx_ev.init.callback = gi2c_ev_cb;
|
||||
gi2c->rx_ev.cmd = MSM_GPI_INIT;
|
||||
gi2c->rx_c->private = &gi2c->rx_ev;
|
||||
ret = dmaengine_slave_config(gi2c->rx_c, NULL);
|
||||
if (ret) {
|
||||
}
|
||||
|
||||
gi2c->tx_ev.init.callback = gi2c_ev_cb;
|
||||
gi2c->tx_ev.init.cb_param = gi2c;
|
||||
gi2c->tx_ev.cmd = MSM_GPI_INIT;
|
||||
gi2c->tx_c->private = &gi2c->tx_ev;
|
||||
ret = dmaengine_slave_config(gi2c->tx_c, NULL);
|
||||
if (ret) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"tx dma slave config ret :%d\n", ret);
|
||||
goto dmaengine_slave_config_fail;
|
||||
}
|
||||
|
||||
gi2c->rx_ev.init.cb_param = gi2c;
|
||||
gi2c->rx_ev.init.callback = gi2c_ev_cb;
|
||||
gi2c->rx_ev.cmd = MSM_GPI_INIT;
|
||||
gi2c->rx_c->private = &gi2c->rx_ev;
|
||||
ret = dmaengine_slave_config(gi2c->rx_c, NULL);
|
||||
if (ret) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"rx dma slave config ret :%d\n", ret);
|
||||
goto dmaengine_slave_config_fail;
|
||||
}
|
||||
|
||||
gi2c->tx_cb.userdata = gi2c;
|
||||
gi2c->rx_cb.userdata = gi2c;
|
||||
gi2c->req_chan = true;
|
||||
|
||||
return ret;
|
||||
|
||||
dmaengine_slave_config_fail:
|
||||
dma_release_channel(gi2c->tx_c);
|
||||
dma_release_channel(gi2c->rx_c);
|
||||
gi2c->tx_c = NULL;
|
||||
gi2c->rx_c = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct msm_gpi_tre *setup_lock_tre(struct geni_i2c_dev *gi2c)
|
||||
{
|
||||
struct msm_gpi_tre *lock_t = &gi2c->lock_t;
|
||||
|
||||
/* lock: chain bit set */
|
||||
lock_t->dword[0] = MSM_GPI_LOCK_TRE_DWORD0;
|
||||
lock_t->dword[1] = MSM_GPI_LOCK_TRE_DWORD1;
|
||||
lock_t->dword[2] = MSM_GPI_LOCK_TRE_DWORD2;
|
||||
/* ieob for le-vm and chain for shared se */
|
||||
if (gi2c->is_shared)
|
||||
lock_t->dword[3] = MSM_GPI_LOCK_TRE_DWORD3(0, 0, 0, 0, 1);
|
||||
else if (gi2c->is_le_vm)
|
||||
lock_t->dword[3] = MSM_GPI_LOCK_TRE_DWORD3(0, 0, 0, 1, 0);
|
||||
|
||||
return lock_t;
|
||||
}
|
||||
|
||||
static struct msm_gpi_tre *setup_cfg0_tre(struct geni_i2c_dev *gi2c)
|
||||
{
|
||||
struct geni_i2c_clk_fld *itr = geni_i2c_clk_map +
|
||||
gi2c->clk_fld_idx;
|
||||
struct msm_gpi_tre *cfg0_t = &gi2c->cfg0_t;
|
||||
|
||||
/* config0 */
|
||||
cfg0_t->dword[0] = MSM_GPI_I2C_CONFIG0_TRE_DWORD0(I2C_PACK_EN,
|
||||
itr->t_cycle, itr->t_high, itr->t_low);
|
||||
cfg0_t->dword[1] = MSM_GPI_I2C_CONFIG0_TRE_DWORD1(0, 0);
|
||||
cfg0_t->dword[2] = MSM_GPI_I2C_CONFIG0_TRE_DWORD2(0,
|
||||
itr->clk_div);
|
||||
cfg0_t->dword[3] = MSM_GPI_I2C_CONFIG0_TRE_DWORD3(0, 0, 0, 0, 1);
|
||||
|
||||
return cfg0_t;
|
||||
}
|
||||
|
||||
static struct msm_gpi_tre *setup_go_tre(struct geni_i2c_dev *gi2c,
|
||||
struct i2c_msg msgs[], int i, int num)
|
||||
{
|
||||
struct msm_gpi_tre *go_t = &gi2c->go_t;
|
||||
u8 op = (msgs[i].flags & I2C_M_RD) ? 2 : 1;
|
||||
int stretch = (i < (num - 1));
|
||||
|
||||
go_t->dword[0] = MSM_GPI_I2C_GO_TRE_DWORD0((stretch << 2),
|
||||
msgs[i].addr, op);
|
||||
go_t->dword[1] = MSM_GPI_I2C_GO_TRE_DWORD1;
|
||||
|
||||
if (msgs[i].flags & I2C_M_RD) {
|
||||
go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(msgs[i].len);
|
||||
/*
|
||||
* For Rx Go tre: Set ieob for non-shared se and for all
|
||||
* but last transfer in shared se
|
||||
*/
|
||||
if (!gi2c->is_shared || (gi2c->is_shared && i != num-1))
|
||||
go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0,
|
||||
0, 1, 0);
|
||||
else
|
||||
go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0,
|
||||
0, 0, 0);
|
||||
} else {
|
||||
/* For Tx Go tre: ieob is not set, chain bit is set */
|
||||
go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(0);
|
||||
go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(0, 0, 0, 0,
|
||||
1);
|
||||
}
|
||||
|
||||
return go_t;
|
||||
}
|
||||
|
||||
static struct msm_gpi_tre *setup_rx_tre(struct geni_i2c_dev *gi2c,
|
||||
struct i2c_msg msgs[], int i, int num)
|
||||
{
|
||||
struct msm_gpi_tre *rx_t = &gi2c->rx_t;
|
||||
|
||||
rx_t->dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph);
|
||||
rx_t->dword[1] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->rx_ph);
|
||||
rx_t->dword[2] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len);
|
||||
/* Set ieot for all Rx/Tx DMA tres */
|
||||
rx_t->dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0);
|
||||
|
||||
return rx_t;
|
||||
}
|
||||
|
||||
static struct msm_gpi_tre *setup_tx_tre(struct geni_i2c_dev *gi2c,
|
||||
struct i2c_msg msgs[], int i, int num)
|
||||
{
|
||||
struct msm_gpi_tre *tx_t = &gi2c->tx_t;
|
||||
|
||||
tx_t->dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph);
|
||||
tx_t->dword[1] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->tx_ph);
|
||||
tx_t->dword[2] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len);
|
||||
if (gi2c->is_shared && i == num-1)
|
||||
/*
|
||||
* For Tx: unlock tre is send for last transfer
|
||||
* so set chain bit for last transfer DMA tre.
|
||||
*/
|
||||
tx_t->dword[3] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 1);
|
||||
else
|
||||
tx_t->dword[3] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0);
|
||||
|
||||
return tx_t;
|
||||
}
|
||||
|
||||
static struct msm_gpi_tre *setup_unlock_tre(struct geni_i2c_dev *gi2c)
|
||||
{
|
||||
struct msm_gpi_tre *unlock_t = &gi2c->unlock_t;
|
||||
|
||||
/* unlock tre: ieob set */
|
||||
unlock_t->dword[0] = MSM_GPI_UNLOCK_TRE_DWORD0;
|
||||
unlock_t->dword[1] = MSM_GPI_UNLOCK_TRE_DWORD1;
|
||||
unlock_t->dword[2] = MSM_GPI_UNLOCK_TRE_DWORD2;
|
||||
unlock_t->dword[3] = MSM_GPI_UNLOCK_TRE_DWORD3(0, 0, 0, 1, 0);
|
||||
|
||||
return unlock_t;
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *geni_i2c_prep_desc
|
||||
(struct geni_i2c_dev *gi2c, struct dma_chan *chan, int segs)
|
||||
{
|
||||
struct dma_async_tx_descriptor *geni_desc = NULL;
|
||||
|
||||
if (chan->chan_id == 0) {
|
||||
geni_desc = dmaengine_prep_slave_sg(gi2c->tx_c, gi2c->tx_sg,
|
||||
segs, DMA_MEM_TO_DEV,
|
||||
(DMA_PREP_INTERRUPT | DMA_CTRL_ACK));
|
||||
if (!geni_desc) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"rx dma slave config ret :%d\n", ret);
|
||||
goto geni_i2c_gsi_xfer_out;
|
||||
"prep_slave_sg for tx failed\n");
|
||||
gi2c->err = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
geni_desc->callback = gi2c_gsi_tx_cb;
|
||||
geni_desc->callback_param = &gi2c->tx_cb;
|
||||
} else {
|
||||
geni_desc = dmaengine_prep_slave_sg(gi2c->rx_c,
|
||||
&gi2c->rx_sg, 1, DMA_DEV_TO_MEM,
|
||||
(DMA_PREP_INTERRUPT | DMA_CTRL_ACK));
|
||||
if (!geni_desc) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"prep_slave_sg for rx failed\n");
|
||||
gi2c->err = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
geni_desc->callback = gi2c_gsi_rx_cb;
|
||||
geni_desc->callback_param = &gi2c->rx_cb;
|
||||
}
|
||||
|
||||
return geni_desc;
|
||||
}
|
||||
|
||||
static int geni_i2c_lock_bus(struct geni_i2c_dev *gi2c)
|
||||
{
|
||||
struct msm_gpi_tre *lock_t = NULL;
|
||||
int ret = 0, timeout = 0;
|
||||
dma_cookie_t tx_cookie;
|
||||
|
||||
if (!gi2c->req_chan) {
|
||||
ret = geni_i2c_gsi_request_channel(gi2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
lock_t = setup_lock_tre(gi2c);
|
||||
sg_init_table(gi2c->tx_sg, 1);
|
||||
sg_set_buf(&gi2c->tx_sg[0], lock_t,
|
||||
sizeof(gi2c->lock_t));
|
||||
|
||||
gi2c->tx_desc = geni_i2c_prep_desc(gi2c, gi2c->tx_c, 1);
|
||||
if (!gi2c->tx_desc) {
|
||||
gi2c->err = -ENOMEM;
|
||||
goto geni_i2c_err_lock_bus;
|
||||
}
|
||||
|
||||
/* Issue TX */
|
||||
tx_cookie = dmaengine_submit(gi2c->tx_desc);
|
||||
dma_async_issue_pending(gi2c->tx_c);
|
||||
|
||||
reinit_completion(&gi2c->xfer);
|
||||
timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
|
||||
if (!timeout) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s timedout\n", __func__);
|
||||
geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base,
|
||||
gi2c->ipcl);
|
||||
gi2c->err = -ETIMEDOUT;
|
||||
goto geni_i2c_err_lock_bus;
|
||||
}
|
||||
return 0;
|
||||
|
||||
geni_i2c_err_lock_bus:
|
||||
if (gi2c->err) {
|
||||
dmaengine_terminate_all(gi2c->tx_c);
|
||||
gi2c->cfg_sent = 0;
|
||||
}
|
||||
return gi2c->err;
|
||||
}
|
||||
|
||||
static void geni_i2c_unlock_bus(struct geni_i2c_dev *gi2c)
|
||||
{
|
||||
struct msm_gpi_tre *unlock_t = NULL;
|
||||
int timeout = 0;
|
||||
dma_cookie_t tx_cookie;
|
||||
|
||||
if (gi2c->gpi_reset)
|
||||
goto geni_i2c_err_unlock_bus;
|
||||
|
||||
unlock_t = setup_unlock_tre(gi2c);
|
||||
sg_init_table(gi2c->tx_sg, 1);
|
||||
sg_set_buf(&gi2c->tx_sg[0], unlock_t,
|
||||
sizeof(gi2c->unlock_t));
|
||||
|
||||
gi2c->tx_desc = geni_i2c_prep_desc(gi2c, gi2c->tx_c, 1);
|
||||
if (!gi2c->tx_desc) {
|
||||
gi2c->err = -ENOMEM;
|
||||
goto geni_i2c_err_unlock_bus;
|
||||
}
|
||||
|
||||
/* Issue TX */
|
||||
tx_cookie = dmaengine_submit(gi2c->tx_desc);
|
||||
dma_async_issue_pending(gi2c->tx_c);
|
||||
|
||||
reinit_completion(&gi2c->xfer);
|
||||
timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
|
||||
if (!timeout) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s failed\n", __func__);
|
||||
geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base,
|
||||
gi2c->ipcl);
|
||||
gi2c->err = -ETIMEDOUT;
|
||||
goto geni_i2c_err_unlock_bus;
|
||||
}
|
||||
|
||||
geni_i2c_err_unlock_bus:
|
||||
if (gi2c->gpi_reset || gi2c->err) {
|
||||
dmaengine_terminate_all(gi2c->tx_c);
|
||||
gi2c->cfg_sent = 0;
|
||||
gi2c->err = 0;
|
||||
gi2c->gpi_reset = false;
|
||||
}
|
||||
}
|
||||
|
||||
static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||
int num)
|
||||
{
|
||||
struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
|
||||
int i, ret = 0, timeout = 0;
|
||||
struct msm_gpi_tre *lock_t = NULL;
|
||||
struct msm_gpi_tre *unlock_t = NULL;
|
||||
struct msm_gpi_tre *cfg0_t = NULL;
|
||||
|
||||
if (!gi2c->req_chan) {
|
||||
ret = geni_i2c_gsi_request_channel(gi2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gi2c->is_shared) {
|
||||
struct msm_gpi_tre *lock_t = &gi2c->lock_t;
|
||||
struct msm_gpi_tre *unlock_t = &gi2c->unlock_t;
|
||||
|
||||
/* lock */
|
||||
lock_t->dword[0] = MSM_GPI_LOCK_TRE_DWORD0;
|
||||
lock_t->dword[1] = MSM_GPI_LOCK_TRE_DWORD1;
|
||||
lock_t->dword[2] = MSM_GPI_LOCK_TRE_DWORD2;
|
||||
lock_t->dword[3] = MSM_GPI_LOCK_TRE_DWORD3(0, 0, 0, 0, 1);
|
||||
|
||||
/* unlock tre: ieob set */
|
||||
unlock_t->dword[0] = MSM_GPI_UNLOCK_TRE_DWORD0;
|
||||
unlock_t->dword[1] = MSM_GPI_UNLOCK_TRE_DWORD1;
|
||||
unlock_t->dword[2] = MSM_GPI_UNLOCK_TRE_DWORD2;
|
||||
unlock_t->dword[3] = MSM_GPI_UNLOCK_TRE_DWORD3(0, 0, 0, 1, 0);
|
||||
lock_t = setup_lock_tre(gi2c);
|
||||
unlock_t = setup_unlock_tre(gi2c);
|
||||
}
|
||||
|
||||
if (!gi2c->cfg_sent) {
|
||||
struct geni_i2c_clk_fld *itr = geni_i2c_clk_map +
|
||||
gi2c->clk_fld_idx;
|
||||
struct msm_gpi_tre *cfg0 = &gi2c->cfg0_t;
|
||||
|
||||
/* config0 */
|
||||
cfg0->dword[0] = MSM_GPI_I2C_CONFIG0_TRE_DWORD0(I2C_PACK_EN,
|
||||
itr->t_cycle,
|
||||
itr->t_high,
|
||||
itr->t_low);
|
||||
cfg0->dword[1] = MSM_GPI_I2C_CONFIG0_TRE_DWORD1(0, 0);
|
||||
cfg0->dword[2] = MSM_GPI_I2C_CONFIG0_TRE_DWORD2(0,
|
||||
itr->clk_div);
|
||||
cfg0->dword[3] = MSM_GPI_I2C_CONFIG0_TRE_DWORD3(0, 0, 0, 0, 1);
|
||||
|
||||
gi2c->tx_cb.userdata = gi2c;
|
||||
gi2c->rx_cb.userdata = gi2c;
|
||||
}
|
||||
if (!gi2c->cfg_sent)
|
||||
cfg0_t = setup_cfg0_tre(gi2c);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
u8 op = (msgs[i].flags & I2C_M_RD) ? 2 : 1;
|
||||
int segs = 3 - op;
|
||||
int index = 0;
|
||||
u8 *dma_buf = NULL;
|
||||
int stretch = (i < (num - 1));
|
||||
dma_cookie_t tx_cookie, rx_cookie;
|
||||
struct msm_gpi_tre *go_t = &gi2c->go_t;
|
||||
struct msm_gpi_tre *go_t = NULL;
|
||||
struct msm_gpi_tre *rx_t = NULL;
|
||||
struct msm_gpi_tre *tx_t = NULL;
|
||||
struct device *rx_dev = gi2c->wrapper_dev;
|
||||
struct device *tx_dev = gi2c->wrapper_dev;
|
||||
|
||||
|
|
@ -569,7 +814,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
sg_init_table(gi2c->tx_sg, segs);
|
||||
if (i == 0)
|
||||
/* Send lock tre for first transfer in a msg */
|
||||
sg_set_buf(&gi2c->tx_sg[index++], &gi2c->lock_t,
|
||||
sg_set_buf(&gi2c->tx_sg[index++], lock_t,
|
||||
sizeof(gi2c->lock_t));
|
||||
} else {
|
||||
sg_init_table(gi2c->tx_sg, segs);
|
||||
|
|
@ -577,35 +822,13 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
|
||||
/* Send cfg tre when cfg not sent already */
|
||||
if (!gi2c->cfg_sent) {
|
||||
sg_set_buf(&gi2c->tx_sg[index++], &gi2c->cfg0_t,
|
||||
sg_set_buf(&gi2c->tx_sg[index++], cfg0_t,
|
||||
sizeof(gi2c->cfg0_t));
|
||||
gi2c->cfg_sent = 1;
|
||||
}
|
||||
|
||||
go_t->dword[0] = MSM_GPI_I2C_GO_TRE_DWORD0((stretch << 2),
|
||||
msgs[i].addr, op);
|
||||
go_t->dword[1] = MSM_GPI_I2C_GO_TRE_DWORD1;
|
||||
|
||||
if (msgs[i].flags & I2C_M_RD) {
|
||||
go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(msgs[i].len);
|
||||
/*
|
||||
* For Rx Go tre: Set ieob for non-shared se and for all
|
||||
* but last transfer in shared se
|
||||
*/
|
||||
if (!gi2c->is_shared || (gi2c->is_shared && i != num-1))
|
||||
go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0,
|
||||
0, 1, 0);
|
||||
else
|
||||
go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0,
|
||||
0, 0, 0);
|
||||
} else {
|
||||
/* For Tx Go tre: ieob is not set, chain bit is set */
|
||||
go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(0);
|
||||
go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(0, 0, 0, 0,
|
||||
1);
|
||||
}
|
||||
|
||||
sg_set_buf(&gi2c->tx_sg[index++], &gi2c->go_t,
|
||||
go_t = setup_go_tre(gi2c, msgs, i, num);
|
||||
sg_set_buf(&gi2c->tx_sg[index++], go_t,
|
||||
sizeof(gi2c->go_t));
|
||||
|
||||
if (msgs[i].flags & I2C_M_RD) {
|
||||
|
|
@ -629,31 +852,17 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
gi2c->dbg_buf_ptr[i].map_buf =
|
||||
(void *)&gi2c->rx_ph;
|
||||
}
|
||||
gi2c->rx_t.dword[0] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph);
|
||||
gi2c->rx_t.dword[1] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->rx_ph);
|
||||
gi2c->rx_t.dword[2] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len);
|
||||
/* Set ieot for all Rx/Tx DMA tres */
|
||||
gi2c->rx_t.dword[3] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0);
|
||||
|
||||
sg_set_buf(&gi2c->rx_sg, &gi2c->rx_t,
|
||||
rx_t = setup_rx_tre(gi2c, msgs, i, num);
|
||||
sg_set_buf(&gi2c->rx_sg, rx_t,
|
||||
sizeof(gi2c->rx_t));
|
||||
gi2c->rx_desc = dmaengine_prep_slave_sg(gi2c->rx_c,
|
||||
&gi2c->rx_sg, 1,
|
||||
DMA_DEV_TO_MEM,
|
||||
(DMA_PREP_INTERRUPT |
|
||||
DMA_CTRL_ACK));
|
||||
|
||||
gi2c->rx_desc =
|
||||
geni_i2c_prep_desc(gi2c, gi2c->rx_c, segs);
|
||||
if (!gi2c->rx_desc) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"prep_slave_sg for rx failed\n");
|
||||
gi2c->err = -ENOMEM;
|
||||
goto geni_i2c_err_prep_sg;
|
||||
}
|
||||
gi2c->rx_desc->callback = gi2c_gsi_rx_cb;
|
||||
gi2c->rx_desc->callback_param = &gi2c->rx_cb;
|
||||
|
||||
/* Issue RX */
|
||||
rx_cookie = dmaengine_submit(gi2c->rx_desc);
|
||||
|
|
@ -679,45 +888,22 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
(void *)&gi2c->tx_ph;
|
||||
}
|
||||
|
||||
gi2c->tx_t.dword[0] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph);
|
||||
gi2c->tx_t.dword[1] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->tx_ph);
|
||||
gi2c->tx_t.dword[2] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len);
|
||||
if (gi2c->is_shared && i == num-1)
|
||||
/*
|
||||
* For Tx: unlock tre is send for last transfer
|
||||
* so set chain bit for last transfer DMA tre.
|
||||
*/
|
||||
gi2c->tx_t.dword[3] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 1);
|
||||
else
|
||||
gi2c->tx_t.dword[3] =
|
||||
MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0);
|
||||
|
||||
sg_set_buf(&gi2c->tx_sg[index++], &gi2c->tx_t,
|
||||
tx_t = setup_tx_tre(gi2c, msgs, i, num);
|
||||
sg_set_buf(&gi2c->tx_sg[index++], tx_t,
|
||||
sizeof(gi2c->tx_t));
|
||||
}
|
||||
|
||||
if (gi2c->is_shared && i == num-1) {
|
||||
/* Send unlock tre at the end of last transfer */
|
||||
sg_set_buf(&gi2c->tx_sg[index++],
|
||||
&gi2c->unlock_t, sizeof(gi2c->unlock_t));
|
||||
unlock_t, sizeof(gi2c->unlock_t));
|
||||
}
|
||||
|
||||
gi2c->tx_desc = dmaengine_prep_slave_sg(gi2c->tx_c, gi2c->tx_sg,
|
||||
segs, DMA_MEM_TO_DEV,
|
||||
(DMA_PREP_INTERRUPT |
|
||||
DMA_CTRL_ACK));
|
||||
gi2c->tx_desc = geni_i2c_prep_desc(gi2c, gi2c->tx_c, segs);
|
||||
if (!gi2c->tx_desc) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"prep_slave_sg for tx failed\n");
|
||||
gi2c->err = -ENOMEM;
|
||||
goto geni_i2c_err_prep_sg;
|
||||
}
|
||||
gi2c->tx_desc->callback = gi2c_gsi_tx_cb;
|
||||
gi2c->tx_desc->callback_param = &gi2c->tx_cb;
|
||||
|
||||
/* Issue TX */
|
||||
tx_cookie = dmaengine_submit(gi2c->tx_desc);
|
||||
|
|
@ -736,8 +922,20 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
}
|
||||
geni_i2c_err_prep_sg:
|
||||
if (gi2c->err) {
|
||||
dmaengine_terminate_all(gi2c->tx_c);
|
||||
gi2c->cfg_sent = 0;
|
||||
if (!gi2c->is_le_vm) {
|
||||
dmaengine_terminate_all(gi2c->tx_c);
|
||||
gi2c->cfg_sent = 0;
|
||||
} else {
|
||||
/* Stop channel in case of error in LE-VM */
|
||||
ret = dmaengine_pause(gi2c->tx_c);
|
||||
if (ret) {
|
||||
gi2c->gpi_reset = true;
|
||||
gi2c->err = ret;
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"Channel cancel failed\n");
|
||||
goto geni_i2c_gsi_xfer_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gi2c->is_shared)
|
||||
/* Resend cfg tre for every new message on shared se */
|
||||
|
|
@ -777,21 +975,14 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
|
|||
return -EACCES;
|
||||
}
|
||||
|
||||
ret = pm_runtime_get_sync(gi2c->dev);
|
||||
if (ret < 0) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"error turning SE resources:%d\n", ret);
|
||||
pm_runtime_put_noidle(gi2c->dev);
|
||||
/* Set device in suspended since resume failed */
|
||||
pm_runtime_set_suspended(gi2c->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gi2c->is_le_vm) {
|
||||
ret = geni_i2c_prepare(gi2c);
|
||||
if (ret) {
|
||||
dev_err(gi2c->dev, "I2C prepare failed\n");
|
||||
pm_runtime_put_sync_suspend(gi2c->dev);
|
||||
if (!gi2c->is_le_vm) {
|
||||
ret = pm_runtime_get_sync(gi2c->dev);
|
||||
if (ret < 0) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"error turning SE resources:%d\n", ret);
|
||||
pm_runtime_put_noidle(gi2c->dev);
|
||||
/* Set device in suspended since resume failed */
|
||||
pm_runtime_set_suspended(gi2c->dev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -950,8 +1141,10 @@ geni_i2c_txn_ret:
|
|||
if (ret == 0)
|
||||
ret = num;
|
||||
|
||||
pm_runtime_mark_last_busy(gi2c->dev);
|
||||
pm_runtime_put_autosuspend(gi2c->dev);
|
||||
if (!gi2c->is_le_vm) {
|
||||
pm_runtime_mark_last_busy(gi2c->dev);
|
||||
pm_runtime_put_autosuspend(gi2c->dev);
|
||||
}
|
||||
gi2c->cur = NULL;
|
||||
gi2c->err = 0;
|
||||
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
|
||||
|
|
@ -1013,6 +1206,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
if (of_property_read_bool(pdev->dev.of_node, "qcom,le-vm")) {
|
||||
gi2c->is_le_vm = true;
|
||||
gi2c->first_resume = true;
|
||||
dev_info(&pdev->dev, "LE-VM usecase\n");
|
||||
}
|
||||
|
||||
|
|
@ -1168,6 +1362,10 @@ static int geni_i2c_resume_noirq(struct device *device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get sync/put sync in LA-VM -> do resources on/off
|
||||
* get sync/put sync in LE-VM -> do lock/unlock gpii
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_PM)
|
||||
static int geni_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
|
|
@ -1177,8 +1375,10 @@ static int geni_i2c_runtime_suspend(struct device *dev)
|
|||
disable_irq(gi2c->irq);
|
||||
|
||||
if (gi2c->is_le_vm) {
|
||||
/* Do not control clk/gpio/icb for LE-VM */
|
||||
return 0;
|
||||
if (!gi2c->first_resume)
|
||||
geni_i2c_unlock_bus(gi2c);
|
||||
else
|
||||
gi2c->first_resume = false;
|
||||
} else if (gi2c->is_shared) {
|
||||
/* Do not unconfigure GPIOs if shared se */
|
||||
se_geni_clks_off(&gi2c->i2c_rsc);
|
||||
|
|
@ -1207,13 +1407,7 @@ static int geni_i2c_runtime_resume(struct device *dev)
|
|||
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* resume is called from probe so for LE,
|
||||
* geni_i2c_prepare can not be called inside
|
||||
* resume as clocks are not on during LE probe.
|
||||
* LA will provide clocks to LE so deferring
|
||||
* the below api call to first transfer in LE.
|
||||
*/
|
||||
|
||||
ret = geni_i2c_prepare(gi2c);
|
||||
if (ret) {
|
||||
dev_err(gi2c->dev, "I2C prepare failed\n");
|
||||
|
|
@ -1222,7 +1416,28 @@ static int geni_i2c_runtime_resume(struct device *dev)
|
|||
|
||||
if (gi2c->se_mode == FIFO_SE_DMA)
|
||||
enable_irq(gi2c->irq);
|
||||
|
||||
} else if (!gi2c->first_resume) {
|
||||
/*
|
||||
* For first resume call in le, do nothing, and in
|
||||
* corresponding first suspend, set the first_resume
|
||||
* flag to false, to enable lock/unlock per resume/suspend
|
||||
* session.
|
||||
*/
|
||||
ret = geni_i2c_prepare(gi2c);
|
||||
if (ret) {
|
||||
dev_err(gi2c->dev, "I2C prepare failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = geni_i2c_lock_bus(gi2c);
|
||||
if (ret) {
|
||||
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
|
||||
"%s failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -179,6 +179,11 @@ enum msm_gpi_tre_type {
|
|||
#define MSM_GPI_RING_PHYS_ADDR_UPPER(ptr) 0
|
||||
#endif
|
||||
|
||||
/* Static GPII */
|
||||
#define STATIC_GPII_BMSK (0x2)
|
||||
#define STATIC_GPII_SHFT (0x1)
|
||||
#define GPI_EV_PRIORITY_BMSK (0x1)
|
||||
|
||||
/* cmds to perform by using dmaengine_slave_config() */
|
||||
enum msm_gpi_ctrl_cmd {
|
||||
MSM_GPI_INIT,
|
||||
|
|
|
|||
Loading…
Reference in a new issue