diff --git a/include/soc/swr-wcd.h b/include/soc/swr-wcd.h index f6ff61a22fe2..360815043709 100644 --- a/include/soc/swr-wcd.h +++ b/include/soc/swr-wcd.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -30,7 +30,8 @@ struct swr_mstr_port { u8 *port; }; -#if IS_ENABLED(CONFIG_SOUNDWIRE_WCD_CTRL) +#if (IS_ENABLED(CONFIG_SOUNDWIRE_WCD_CTRL) || \ + IS_ENABLED(CONFIG_SOUNDWIRE_MSTR_CTRL)) extern int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data); #else /* CONFIG_SOUNDWIRE_WCD_CTRL */ static inline int swrm_wcd_notify(struct platform_device *pdev, u32 id, diff --git a/soc/Kbuild b/soc/Kbuild index de56a2b07374..acee7f646540 100644 --- a/soc/Kbuild +++ b/soc/Kbuild @@ -150,6 +150,7 @@ obj-$(CONFIG_SOUNDWIRE) += swr_dlkm.o swr_dlkm-y := $(SWR_OBJS) obj-$(CONFIG_SOUNDWIRE_WCD_CTRL) += swr_ctrl_dlkm.o +obj-$(CONFIG_SOUNDWIRE_MSTR_CTRL) += swr_ctrl_dlkm.o swr_ctrl_dlkm-y := $(SWR_CTRL_OBJS) # inject some build related information diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c index 4c5c3bd21354..68354b81367f 100644 --- a/soc/swr-mstr-ctrl.c +++ b/soc/swr-mstr-ctrl.c @@ -69,6 +69,8 @@ enum { #define SWR_MSTR_RD_BUF_LEN 8 #define SWR_MSTR_WR_BUF_LEN 32 +#define MAX_FIFO_RD_FAIL_RETRY 3 + static struct swr_mstr_ctrl *dbgswrm; static struct dentry *debugfs_swrm_dent; static struct dentry *debugfs_peek; @@ -243,7 +245,7 @@ static int swrm_clk_request(struct swr_mstr_ctrl *swrm, bool enable) static int swrm_ahb_write(struct swr_mstr_ctrl *swrm, u16 reg, u32 *value) { - u32 temp = (u32)(*value) & 0x000000FF; + u32 temp = (u32)(*value); int ret; ret = swrm_clk_request(swrm, TRUE); @@ -253,7 +255,7 @@ static int swrm_ahb_write(struct swr_mstr_ctrl *swrm, iowrite32(temp, swrm->swrm_dig_base + reg); - swrm_clk_request(swrm, TRUE); + swrm_clk_request(swrm, FALSE); return 0; } @@ -261,7 +263,7 @@ static int swrm_ahb_write(struct swr_mstr_ctrl *swrm, static int swrm_ahb_read(struct swr_mstr_ctrl *swrm, u16 reg, u32 *value) { - u32 temp; + u32 temp = 0; int ret; ret = swrm_clk_request(swrm, TRUE); @@ -270,7 +272,7 @@ static int swrm_ahb_read(struct swr_mstr_ctrl *swrm, return -EINVAL; temp = ioread32(swrm->swrm_dig_base + reg); - *value = (u8)temp; + *value = temp; swrm_clk_request(swrm, FALSE); return 0; } @@ -302,8 +304,11 @@ static int swr_master_bulk_write(struct swr_mstr_ctrl *swrm, u32 *reg_addr, if (swrm->bulk_write) swrm->bulk_write(swrm->handle, reg_addr, val, length); else { - for (i = 0; i < length; i++) + for (i = 0; i < length; i++) { + /* wait for FIFO WR command to complete to avoid overflow */ + usleep_range(100, 105); swr_master_write(swrm, reg_addr[i], val[i]); + } } return 0; } @@ -318,10 +323,8 @@ static int swrm_get_port_config(struct swr_mstr_ctrl *swrm) u8 master_device_id; int i; - if (swrm->version == SWRM_VERSION_1_5) - master_device_id = swr_master_read(swrm, SWRM_COMP_MASTER_ID); - else - master_device_id = MASTER_ID_WSA; + /* update device_id for tx/rx */ + master_device_id = MASTER_ID_WSA; switch (master_device_id & MASTER_ID_MASK) { case MASTER_ID_WSA: @@ -398,15 +401,30 @@ static int swrm_cmd_fifo_rd_cmd(struct swr_mstr_ctrl *swrm, int *cmd_data, u32 len) { u32 val; + u32 retry_attempt = 0; val = swrm_get_packed_reg_val(&swrm->rcmd_id, len, dev_addr, reg_addr); + /* wait for FIFO RD to complete to avoid overflow */ + usleep_range(100, 105); swr_master_write(swrm, SWRM_CMD_FIFO_RD_CMD, val); - + /* wait for FIFO RD CMD complete to avoid overflow */ + usleep_range(250, 255); +retry_read: *cmd_data = swr_master_read(swrm, SWRM_CMD_FIFO_RD_FIFO_ADDR); dev_dbg(swrm->dev, "%s: reg: 0x%x, cmd_id: 0x%x, dev_num: 0x%x, cmd_data: 0x%x\n", __func__, reg_addr, cmd_id, dev_addr, *cmd_data); - + if ((((*cmd_data) & 0xF00) >> 8) != swrm->rcmd_id) { + if (retry_attempt < MAX_FIFO_RD_FAIL_RETRY) { + /* wait 500 us before retry on fifo read failure */ + usleep_range(500, 505); + retry_attempt++; + goto retry_read; + } else { + dev_err_ratelimited(swrm->dev, + "%s: failed to read fifo\n", __func__); + } + } return 0; } @@ -422,12 +440,12 @@ static int swrm_cmd_fifo_wr_cmd(struct swr_mstr_ctrl *swrm, u8 cmd_data, else val = swrm_get_packed_reg_val(&cmd_id, cmd_data, dev_addr, reg_addr); - dev_dbg(swrm->dev, - "%s: reg: 0x%x, cmd_id: 0x%x, dev_num: 0x%x, cmd_data: 0x%x\n", - __func__, reg_addr, cmd_id, dev_addr, cmd_data); + "%s: reg: 0x%x, cmd_id: 0x%x, val:0x%x, dev_num: 0x%x, cmd_data: 0x%x\n", + __func__, reg_addr, cmd_id, val, dev_addr, cmd_data); + /* wait for FIFO WR command to complete to avoid overflow */ + usleep_range(250, 255); swr_master_write(swrm, SWRM_CMD_FIFO_WR_CMD, val); - if (cmd_id == 0xF) { /* * sleep for 10ms for MSM soundwire variant to allow broadcast @@ -806,9 +824,8 @@ static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable) } mutex_lock(&swrm->mlock); - /* wakeup soundwire master if in sleep */ - pm_runtime_get_sync(swrm->dev); - + if (enable) + pm_runtime_get_sync(swrm->dev); bank = get_inactive_bank_num(swrm); if (enable) { @@ -816,6 +833,8 @@ static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable) if (ret) { /* cannot accommodate ports */ swrm_cleanup_disabled_port_reqs(master); + pm_runtime_mark_last_busy(swrm->dev); + pm_runtime_put_autosuspend(swrm->dev); mutex_unlock(&swrm->mlock); return -EINVAL; } @@ -858,8 +877,6 @@ static int swrm_slvdev_datapath_control(struct swr_master *master, bool enable) else { swrm_disable_ports(master, inactive_bank); swrm_cleanup_disabled_port_reqs(master); - } - if (!swrm_is_port_en(master)) { dev_dbg(&master->dev, "%s: pm_runtime auto suspend triggered\n", __func__); pm_runtime_mark_last_busy(swrm->dev); @@ -1300,8 +1317,9 @@ static int swrm_probe(struct platform_device *pdev) ret = -EINVAL; goto err_pdata_fail; } - if (!(of_property_read_u32(pdev->dev.of_node, "swrm-io-base", NULL))) - swrm->swrm_base_reg = of_property_read_u32(pdev->dev.of_node, + if (!(of_property_read_u32(pdev->dev.of_node, + "swrm-io-base", &swrm->swrm_base_reg))) + ret = of_property_read_u32(pdev->dev.of_node, "swrm-io-base", &swrm->swrm_base_reg); if (!swrm->swrm_base_reg) { swrm->read = pdata->read; @@ -1414,6 +1432,19 @@ static int swrm_probe(struct platform_device *pdev) for (i = 0 ; i < SWR_MSTR_PORT_LEN; i++) INIT_LIST_HEAD(&swrm->mport_cfg[i].port_req_list); + ret = of_property_read_u32(swrm->dev->of_node, "qcom,swr-num-dev", + &swrm->num_dev); + if (ret) { + dev_dbg(&pdev->dev, "%s: Looking up %s property failed\n", + __func__, "qcom,swr-num-dev"); + } else { + if (swrm->num_dev > SWR_MAX_SLAVE_DEVICES) { + dev_err(&pdev->dev, "%s: num_dev %d > max limit %d\n", + __func__, swrm->num_dev, SWR_MAX_SLAVE_DEVICES); + ret = -EINVAL; + goto err_pdata_fail; + } + } if (swrm->reg_irq) { ret = swrm->reg_irq(swrm->handle, swr_mstr_interrupt, swrm, SWR_IRQ_REGISTER); @@ -1427,12 +1458,12 @@ static int swrm_probe(struct platform_device *pdev) if (swrm->irq < 0) { dev_err(swrm->dev, "%s() error getting irq hdle: %d\n", __func__, swrm->irq); - goto err_pdata_fail; + goto err_irq_fail; } ret = request_threaded_irq(swrm->irq, NULL, swr_mstr_interrupt, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "swr_master_irq", swrm); if (ret) { dev_err(swrm->dev, "%s: Failed to request irq %d\n", diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h index 75d79c23ceb0..17d6c938c72f 100644 --- a/soc/swr-mstr-ctrl.h +++ b/soc/swr-mstr-ctrl.h @@ -30,6 +30,7 @@ #define SWR_MAX_CH_PER_PORT 8 +#define SWR_MAX_SLAVE_DEVICES 11 enum { SWR_MSTR_PAUSE,