2020-01-13 16:21:53 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019, Linaro Limited
# include <linux/clk.h>
# include <linux/completion.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
2021-09-07 13:56:36 +03:00
# include <linux/debugfs.h>
2020-01-13 16:21:53 +03:00
# include <linux/of.h>
# include <linux/of_irq.h>
2022-02-28 20:25:26 +03:00
# include <linux/pm_runtime.h>
2020-01-13 16:21:53 +03:00
# include <linux/regmap.h>
2022-05-18 15:42:35 +03:00
# include <linux/reset.h>
2020-01-13 16:21:53 +03:00
# include <linux/slab.h>
2022-02-28 20:25:28 +03:00
# include <linux/pm_wakeirq.h>
2020-01-13 16:21:53 +03:00
# include <linux/slimbus.h>
# include <linux/soundwire/sdw.h>
# include <linux/soundwire/sdw_registers.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include "bus.h"
2022-02-28 20:25:26 +03:00
# define SWRM_COMP_SW_RESET 0x008
# define SWRM_COMP_STATUS 0x014
2022-10-26 14:02:10 +03:00
# define SWRM_LINK_MANAGER_EE 0x018
# define SWRM_EE_CPU 1
2022-02-28 20:25:26 +03:00
# define SWRM_FRM_GEN_ENABLED BIT(0)
2023-02-22 17:44:11 +03:00
# define SWRM_VERSION_1_3_0 0x01030000
# define SWRM_VERSION_1_5_1 0x01050001
# define SWRM_VERSION_1_7_0 0x01070000
2023-04-18 12:54:46 +03:00
# define SWRM_VERSION_2_0_0 0x02000000
2020-01-13 16:21:53 +03:00
# define SWRM_COMP_HW_VERSION 0x00
# define SWRM_COMP_CFG_ADDR 0x04
# define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1)
# define SWRM_COMP_CFG_ENABLE_MSK BIT(0)
# define SWRM_COMP_PARAMS 0x100
2021-04-01 12:00:58 +03:00
# define SWRM_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(14, 10)
# define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15)
2020-01-13 16:21:53 +03:00
# define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0)
# define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5)
2022-02-28 20:25:26 +03:00
# define SWRM_COMP_MASTER_ID 0x104
2023-04-18 12:54:45 +03:00
# define SWRM_V1_3_INTERRUPT_STATUS 0x200
2023-04-18 12:54:46 +03:00
# define SWRM_V2_0_INTERRUPT_STATUS 0x5000
2020-01-13 16:21:53 +03:00
# define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0)
2021-03-30 17:47:16 +03:00
# define SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ BIT(0)
2020-01-13 16:21:53 +03:00
# define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED BIT(1)
# define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2)
2021-03-30 17:47:16 +03:00
# define SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET BIT(3)
# define SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW BIT(4)
# define SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW BIT(5)
# define SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW BIT(6)
2020-01-13 16:21:53 +03:00
# define SWRM_INTERRUPT_STATUS_CMD_ERROR BIT(7)
2021-03-30 17:47:16 +03:00
# define SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION BIT(8)
# define SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH BIT(9)
2020-01-13 16:21:53 +03:00
# define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10)
2023-04-18 12:54:46 +03:00
# define SWRM_INTERRUPT_STATUS_AUTO_ENUM_FAILED BIT(11)
# define SWRM_INTERRUPT_STATUS_AUTO_ENUM_TABLE_IS_FULL BIT(12)
2023-04-18 12:54:47 +03:00
# define SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2 BIT(13)
# define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2 BIT(14)
# define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP BIT(16)
2021-03-30 17:47:16 +03:00
# define SWRM_INTERRUPT_MAX 17
2023-04-18 12:54:45 +03:00
# define SWRM_V1_3_INTERRUPT_MASK_ADDR 0x204
# define SWRM_V1_3_INTERRUPT_CLEAR 0x208
2023-04-18 12:54:46 +03:00
# define SWRM_V2_0_INTERRUPT_CLEAR 0x5008
2023-04-18 12:54:45 +03:00
# define SWRM_V1_3_INTERRUPT_CPU_EN 0x210
2023-04-18 12:54:46 +03:00
# define SWRM_V2_0_INTERRUPT_CPU_EN 0x5004
2023-04-18 12:54:45 +03:00
# define SWRM_V1_3_CMD_FIFO_WR_CMD 0x300
2023-04-18 12:54:46 +03:00
# define SWRM_V2_0_CMD_FIFO_WR_CMD 0x5020
2023-04-18 12:54:45 +03:00
# define SWRM_V1_3_CMD_FIFO_RD_CMD 0x304
2023-04-18 12:54:46 +03:00
# define SWRM_V2_0_CMD_FIFO_RD_CMD 0x5024
2020-01-13 16:21:53 +03:00
# define SWRM_CMD_FIFO_CMD 0x308
2021-03-30 17:47:15 +03:00
# define SWRM_CMD_FIFO_FLUSH 0x1
2023-04-18 12:54:45 +03:00
# define SWRM_V1_3_CMD_FIFO_STATUS 0x30C
2023-04-18 12:54:46 +03:00
# define SWRM_V2_0_CMD_FIFO_STATUS 0x5050
2021-04-01 12:00:58 +03:00
# define SWRM_RD_CMD_FIFO_CNT_MASK GENMASK(20, 16)
# define SWRM_WR_CMD_FIFO_CNT_MASK GENMASK(12, 8)
2020-01-13 16:21:53 +03:00
# define SWRM_CMD_FIFO_CFG_ADDR 0x314
2021-03-30 17:47:13 +03:00
# define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE BIT(31)
2020-01-13 16:21:53 +03:00
# define SWRM_RD_WR_CMD_RETRIES 0x7
2023-04-18 12:54:45 +03:00
# define SWRM_V1_3_CMD_FIFO_RD_FIFO_ADDR 0x318
2023-04-18 12:54:46 +03:00
# define SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR 0x5040
2021-03-30 17:47:15 +03:00
# define SWRM_RD_FIFO_CMD_ID_MASK GENMASK(11, 8)
2020-01-13 16:21:53 +03:00
# define SWRM_ENUMERATOR_CFG_ADDR 0x500
2021-03-30 17:47:18 +03:00
# define SWRM_ENUMERATOR_SLAVE_DEV_ID_1(m) (0x530 + 0x8 * (m))
# define SWRM_ENUMERATOR_SLAVE_DEV_ID_2(m) (0x534 + 0x8 * (m))
2020-01-13 16:21:53 +03:00
# define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m))
# define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0)
# define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3)
2021-03-30 17:47:14 +03:00
# define SWRM_MCP_BUS_CTRL 0x1044
# define SWRM_MCP_BUS_CLK_START BIT(1)
2020-01-13 16:21:53 +03:00
# define SWRM_MCP_CFG_ADDR 0x1048
# define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK GENMASK(21, 17)
# define SWRM_DEF_CMD_NO_PINGS 0x1f
# define SWRM_MCP_STATUS 0x104C
# define SWRM_MCP_STATUS_BANK_NUM_MASK BIT(0)
# define SWRM_MCP_SLV_STATUS 0x1090
# define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0)
2021-03-30 17:47:16 +03:00
# define SWRM_MCP_SLV_STATUS_SZ 2
2020-01-13 16:21:53 +03:00
# define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m)
2021-03-30 17:47:12 +03:00
# define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m)
# define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1))
# define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m)
# define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m)
2020-09-17 15:01:37 +03:00
# define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m)
2023-04-18 12:54:43 +03:00
# define SWRM_DP_SAMPLECTRL2_BANK(n, m) (0x113C + 0x100 * (n - 1) + 0x40 * m)
2021-03-30 17:47:12 +03:00
# define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1))
2023-04-18 12:54:45 +03:00
# define SWR_V1_3_MSTR_MAX_REG_ADDR 0x1740
2023-04-18 12:54:46 +03:00
# define SWR_V2_0_MSTR_MAX_REG_ADDR 0x50ac
# define SWRM_V2_0_CLK_CTRL 0x5060
# define SWRM_V2_0_CLK_CTRL_CLK_START BIT(0)
# define SWRM_V2_0_LINK_STATUS 0x5064
2021-03-30 17:47:12 +03:00
2020-01-13 16:21:53 +03:00
# define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18
# define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10
# define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08
# define SWRM_AHB_BRIDGE_WR_DATA_0 0xc85
# define SWRM_AHB_BRIDGE_WR_ADDR_0 0xc89
# define SWRM_AHB_BRIDGE_RD_ADDR_0 0xc8d
# define SWRM_AHB_BRIDGE_RD_DATA_0 0xc91
# define SWRM_REG_VAL_PACK(data, dev, id, reg) \
( ( reg ) | ( ( id ) < < 16 ) | ( ( dev ) < < 20 ) | ( ( data ) < < 24 ) )
2023-04-18 12:54:47 +03:00
# define MAX_FREQ_NUM 1
# define TIMEOUT_MS 100
# define QCOM_SWRM_MAX_RD_LEN 0x1
# define QCOM_SDW_MAX_PORTS 14
# define DEFAULT_CLK_FREQ 9600000
# define SWRM_MAX_DAIS 0xF
# define SWR_INVALID_PARAM 0xFF
# define SWR_HSTOP_MAX_VAL 0xF
# define SWR_HSTART_MIN_VAL 0x0
# define SWR_BROADCAST_CMD_ID 0x0F
# define SWR_MAX_CMD_ID 14
# define MAX_FIFO_RD_RETRY 3
# define SWR_OVERFLOW_RETRY_COUNT 30
# define SWRM_LINK_STATUS_RETRY_CNT 100
2022-02-28 20:25:26 +03:00
enum {
MASTER_ID_WSA = 1 ,
MASTER_ID_RX ,
MASTER_ID_TX
} ;
2020-01-13 16:21:53 +03:00
struct qcom_swrm_port_config {
2023-04-18 12:54:43 +03:00
u16 si ;
2020-01-13 16:21:53 +03:00
u8 off1 ;
u8 off2 ;
2020-09-17 15:01:37 +03:00
u8 bp_mode ;
2021-03-30 17:47:12 +03:00
u8 hstart ;
u8 hstop ;
u8 word_length ;
u8 blk_group_count ;
u8 lane_control ;
2020-01-13 16:21:53 +03:00
} ;
2023-04-18 12:54:45 +03:00
/*
* Internal IDs for different register layouts . Only few registers differ per
* each variant , so the list of IDs below does not include all of registers .
*/
enum {
SWRM_REG_FRAME_GEN_ENABLED ,
SWRM_REG_INTERRUPT_STATUS ,
SWRM_REG_INTERRUPT_MASK_ADDR ,
SWRM_REG_INTERRUPT_CLEAR ,
SWRM_REG_INTERRUPT_CPU_EN ,
SWRM_REG_CMD_FIFO_WR_CMD ,
SWRM_REG_CMD_FIFO_RD_CMD ,
SWRM_REG_CMD_FIFO_STATUS ,
SWRM_REG_CMD_FIFO_RD_FIFO_ADDR ,
} ;
2020-01-13 16:21:53 +03:00
struct qcom_swrm_ctrl {
struct sdw_bus bus ;
struct device * dev ;
struct regmap * regmap ;
2023-04-18 12:54:45 +03:00
u32 max_reg ;
const unsigned int * reg_layout ;
2020-09-05 20:39:04 +03:00
void __iomem * mmio ;
2022-05-18 15:42:35 +03:00
struct reset_control * audio_cgcr ;
2021-09-07 13:56:36 +03:00
# ifdef CONFIG_DEBUG_FS
struct dentry * debugfs ;
# endif
2021-03-30 17:47:15 +03:00
struct completion broadcast ;
2021-03-30 17:47:19 +03:00
struct completion enumeration ;
2020-01-13 16:21:53 +03:00
/* Port alloc/free lock */
struct mutex port_lock ;
struct clk * hclk ;
int irq ;
unsigned int version ;
2022-02-28 20:25:28 +03:00
int wake_irq ;
2020-01-13 16:21:53 +03:00
int num_din_ports ;
int num_dout_ports ;
2020-09-17 15:01:38 +03:00
int cols_index ;
int rows_index ;
2020-01-13 16:21:53 +03:00
unsigned long dout_port_mask ;
unsigned long din_port_mask ;
2021-03-30 17:47:16 +03:00
u32 intr_mask ;
2021-03-30 17:47:15 +03:00
u8 rcmd_id ;
u8 wcmd_id ;
2023-06-01 13:25:25 +03:00
/* Port numbers are 1 - 14 */
struct qcom_swrm_port_config pconfig [ QCOM_SDW_MAX_PORTS + 1 ] ;
2020-01-13 16:21:53 +03:00
struct sdw_stream_runtime * sruntime [ SWRM_MAX_DAIS ] ;
2022-07-08 13:47:47 +03:00
enum sdw_slave_status status [ SDW_MAX_DEVICES + 1 ] ;
2020-01-13 16:21:53 +03:00
int ( * reg_read ) ( struct qcom_swrm_ctrl * ctrl , int reg , u32 * val ) ;
int ( * reg_write ) ( struct qcom_swrm_ctrl * ctrl , int reg , int val ) ;
2021-03-30 17:47:18 +03:00
u32 slave_status ;
2021-04-01 12:00:58 +03:00
u32 wr_fifo_depth ;
u32 rd_fifo_depth ;
2022-02-28 20:25:26 +03:00
bool clock_stop_not_supported ;
2020-01-13 16:21:53 +03:00
} ;
2020-09-17 15:01:38 +03:00
struct qcom_swrm_data {
u32 default_cols ;
u32 default_rows ;
2022-07-01 10:17:06 +03:00
bool sw_clk_gate_required ;
2023-04-18 12:54:45 +03:00
u32 max_reg ;
const unsigned int * reg_layout ;
} ;
static const unsigned int swrm_v1_3_reg_layout [ ] = {
[ SWRM_REG_FRAME_GEN_ENABLED ] = SWRM_COMP_STATUS ,
[ SWRM_REG_INTERRUPT_STATUS ] = SWRM_V1_3_INTERRUPT_STATUS ,
[ SWRM_REG_INTERRUPT_MASK_ADDR ] = SWRM_V1_3_INTERRUPT_MASK_ADDR ,
[ SWRM_REG_INTERRUPT_CLEAR ] = SWRM_V1_3_INTERRUPT_CLEAR ,
[ SWRM_REG_INTERRUPT_CPU_EN ] = SWRM_V1_3_INTERRUPT_CPU_EN ,
[ SWRM_REG_CMD_FIFO_WR_CMD ] = SWRM_V1_3_CMD_FIFO_WR_CMD ,
[ SWRM_REG_CMD_FIFO_RD_CMD ] = SWRM_V1_3_CMD_FIFO_RD_CMD ,
[ SWRM_REG_CMD_FIFO_STATUS ] = SWRM_V1_3_CMD_FIFO_STATUS ,
[ SWRM_REG_CMD_FIFO_RD_FIFO_ADDR ] = SWRM_V1_3_CMD_FIFO_RD_FIFO_ADDR ,
2020-09-17 15:01:38 +03:00
} ;
2022-03-02 15:43:01 +03:00
static const struct qcom_swrm_data swrm_v1_3_data = {
2020-09-17 15:01:38 +03:00
. default_rows = 48 ,
. default_cols = 16 ,
2023-04-18 12:54:45 +03:00
. max_reg = SWR_V1_3_MSTR_MAX_REG_ADDR ,
. reg_layout = swrm_v1_3_reg_layout ,
2020-09-17 15:01:38 +03:00
} ;
2022-03-02 15:43:01 +03:00
static const struct qcom_swrm_data swrm_v1_5_data = {
2020-09-17 15:01:38 +03:00
. default_rows = 50 ,
. default_cols = 16 ,
2023-04-18 12:54:45 +03:00
. max_reg = SWR_V1_3_MSTR_MAX_REG_ADDR ,
. reg_layout = swrm_v1_3_reg_layout ,
2020-09-17 15:01:38 +03:00
} ;
2022-07-01 10:17:07 +03:00
static const struct qcom_swrm_data swrm_v1_6_data = {
. default_rows = 50 ,
. default_cols = 16 ,
. sw_clk_gate_required = true ,
2023-04-18 12:54:45 +03:00
. max_reg = SWR_V1_3_MSTR_MAX_REG_ADDR ,
. reg_layout = swrm_v1_3_reg_layout ,
2022-07-01 10:17:07 +03:00
} ;
2023-04-18 12:54:46 +03:00
static const unsigned int swrm_v2_0_reg_layout [ ] = {
[ SWRM_REG_FRAME_GEN_ENABLED ] = SWRM_V2_0_LINK_STATUS ,
[ SWRM_REG_INTERRUPT_STATUS ] = SWRM_V2_0_INTERRUPT_STATUS ,
[ SWRM_REG_INTERRUPT_MASK_ADDR ] = 0 , /* Not present */
[ SWRM_REG_INTERRUPT_CLEAR ] = SWRM_V2_0_INTERRUPT_CLEAR ,
[ SWRM_REG_INTERRUPT_CPU_EN ] = SWRM_V2_0_INTERRUPT_CPU_EN ,
[ SWRM_REG_CMD_FIFO_WR_CMD ] = SWRM_V2_0_CMD_FIFO_WR_CMD ,
[ SWRM_REG_CMD_FIFO_RD_CMD ] = SWRM_V2_0_CMD_FIFO_RD_CMD ,
[ SWRM_REG_CMD_FIFO_STATUS ] = SWRM_V2_0_CMD_FIFO_STATUS ,
[ SWRM_REG_CMD_FIFO_RD_FIFO_ADDR ] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR ,
} ;
static const struct qcom_swrm_data swrm_v2_0_data = {
. default_rows = 50 ,
. default_cols = 16 ,
. sw_clk_gate_required = true ,
. max_reg = SWR_V2_0_MSTR_MAX_REG_ADDR ,
. reg_layout = swrm_v2_0_reg_layout ,
} ;
2020-01-13 16:21:53 +03:00
# define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)
2020-09-05 20:39:02 +03:00
static int qcom_swrm_ahb_reg_read ( struct qcom_swrm_ctrl * ctrl , int reg ,
2020-01-13 16:21:53 +03:00
u32 * val )
{
struct regmap * wcd_regmap = ctrl - > regmap ;
int ret ;
/* pg register + offset */
ret = regmap_bulk_write ( wcd_regmap , SWRM_AHB_BRIDGE_RD_ADDR_0 ,
( u8 * ) & reg , 4 ) ;
if ( ret < 0 )
return SDW_CMD_FAIL ;
ret = regmap_bulk_read ( wcd_regmap , SWRM_AHB_BRIDGE_RD_DATA_0 ,
val , 4 ) ;
if ( ret < 0 )
return SDW_CMD_FAIL ;
return SDW_CMD_OK ;
}
static int qcom_swrm_ahb_reg_write ( struct qcom_swrm_ctrl * ctrl ,
int reg , int val )
{
struct regmap * wcd_regmap = ctrl - > regmap ;
int ret ;
/* pg register + offset */
ret = regmap_bulk_write ( wcd_regmap , SWRM_AHB_BRIDGE_WR_DATA_0 ,
( u8 * ) & val , 4 ) ;
if ( ret )
return SDW_CMD_FAIL ;
/* write address register */
ret = regmap_bulk_write ( wcd_regmap , SWRM_AHB_BRIDGE_WR_ADDR_0 ,
( u8 * ) & reg , 4 ) ;
if ( ret )
return SDW_CMD_FAIL ;
return SDW_CMD_OK ;
}
2020-09-05 20:39:04 +03:00
static int qcom_swrm_cpu_reg_read ( struct qcom_swrm_ctrl * ctrl , int reg ,
u32 * val )
{
* val = readl ( ctrl - > mmio + reg ) ;
return SDW_CMD_OK ;
}
static int qcom_swrm_cpu_reg_write ( struct qcom_swrm_ctrl * ctrl , int reg ,
int val )
{
writel ( val , ctrl - > mmio + reg ) ;
return SDW_CMD_OK ;
}
2021-03-30 17:47:15 +03:00
static u32 swrm_get_packed_reg_val ( u8 * cmd_id , u8 cmd_data ,
u8 dev_addr , u16 reg_addr )
2020-01-13 16:21:53 +03:00
{
u32 val ;
2021-03-30 17:47:15 +03:00
u8 id = * cmd_id ;
2020-01-13 16:21:53 +03:00
2021-03-30 17:47:15 +03:00
if ( id ! = SWR_BROADCAST_CMD_ID ) {
if ( id < SWR_MAX_CMD_ID )
id + = 1 ;
else
id = 0 ;
* cmd_id = id ;
}
val = SWRM_REG_VAL_PACK ( cmd_data , dev_addr , id , reg_addr ) ;
2020-01-13 16:21:53 +03:00
2021-03-30 17:47:15 +03:00
return val ;
2020-01-13 16:21:53 +03:00
}
2023-04-18 12:54:44 +03:00
static int swrm_wait_for_rd_fifo_avail ( struct qcom_swrm_ctrl * ctrl )
2021-04-01 12:00:58 +03:00
{
u32 fifo_outstanding_data , value ;
int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT ;
do {
/* Check for fifo underflow during read */
2023-04-18 12:54:45 +03:00
ctrl - > reg_read ( ctrl , ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_STATUS ] ,
& value ) ;
2021-04-01 12:00:58 +03:00
fifo_outstanding_data = FIELD_GET ( SWRM_RD_CMD_FIFO_CNT_MASK , value ) ;
/* Check if read data is available in read fifo */
if ( fifo_outstanding_data > 0 )
return 0 ;
usleep_range ( 500 , 510 ) ;
} while ( fifo_retry_count - - ) ;
if ( fifo_outstanding_data = = 0 ) {
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev , " %s err read underflow \n " , __func__ ) ;
2021-04-01 12:00:58 +03:00
return - EIO ;
}
return 0 ;
}
2023-04-18 12:54:44 +03:00
static int swrm_wait_for_wr_fifo_avail ( struct qcom_swrm_ctrl * ctrl )
2021-04-01 12:00:58 +03:00
{
u32 fifo_outstanding_cmds , value ;
int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT ;
do {
/* Check for fifo overflow during write */
2023-04-18 12:54:45 +03:00
ctrl - > reg_read ( ctrl , ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_STATUS ] ,
& value ) ;
2021-04-01 12:00:58 +03:00
fifo_outstanding_cmds = FIELD_GET ( SWRM_WR_CMD_FIFO_CNT_MASK , value ) ;
/* Check for space in write fifo before writing */
2023-04-18 12:54:44 +03:00
if ( fifo_outstanding_cmds < ctrl - > wr_fifo_depth )
2021-04-01 12:00:58 +03:00
return 0 ;
usleep_range ( 500 , 510 ) ;
} while ( fifo_retry_count - - ) ;
2023-04-18 12:54:44 +03:00
if ( fifo_outstanding_cmds = = ctrl - > wr_fifo_depth ) {
dev_err_ratelimited ( ctrl - > dev , " %s err write overflow \n " , __func__ ) ;
2021-04-01 12:00:58 +03:00
return - EIO ;
}
return 0 ;
}
2021-03-30 17:47:15 +03:00
2023-05-25 16:38:10 +03:00
static bool swrm_wait_for_wr_fifo_done ( struct qcom_swrm_ctrl * ctrl )
{
u32 fifo_outstanding_cmds , value ;
int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT ;
/* Check for fifo overflow during write */
ctrl - > reg_read ( ctrl , ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_STATUS ] , & value ) ;
fifo_outstanding_cmds = FIELD_GET ( SWRM_WR_CMD_FIFO_CNT_MASK , value ) ;
if ( fifo_outstanding_cmds ) {
while ( fifo_retry_count ) {
usleep_range ( 500 , 510 ) ;
ctrl - > reg_read ( ctrl , ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_STATUS ] , & value ) ;
fifo_outstanding_cmds = FIELD_GET ( SWRM_WR_CMD_FIFO_CNT_MASK , value ) ;
fifo_retry_count - - ;
if ( fifo_outstanding_cmds = = 0 )
return true ;
}
} else {
return true ;
}
return false ;
}
2023-04-18 12:54:44 +03:00
static int qcom_swrm_cmd_fifo_wr_cmd ( struct qcom_swrm_ctrl * ctrl , u8 cmd_data ,
2021-03-30 17:47:15 +03:00
u8 dev_addr , u16 reg_addr )
2020-01-13 16:21:53 +03:00
{
2021-03-30 17:47:15 +03:00
u32 val ;
int ret = 0 ;
u8 cmd_id = 0x0 ;
2020-01-13 16:21:53 +03:00
2021-03-30 17:47:15 +03:00
if ( dev_addr = = SDW_BROADCAST_DEV_NUM ) {
cmd_id = SWR_BROADCAST_CMD_ID ;
val = swrm_get_packed_reg_val ( & cmd_id , cmd_data ,
dev_addr , reg_addr ) ;
} else {
2023-04-18 12:54:44 +03:00
val = swrm_get_packed_reg_val ( & ctrl - > wcmd_id , cmd_data ,
2021-03-30 17:47:15 +03:00
dev_addr , reg_addr ) ;
}
2020-01-13 16:21:53 +03:00
2023-04-18 12:54:44 +03:00
if ( swrm_wait_for_wr_fifo_avail ( ctrl ) )
2021-04-01 12:00:58 +03:00
return SDW_CMD_FAIL_OTHER ;
2022-10-26 14:02:05 +03:00
if ( cmd_id = = SWR_BROADCAST_CMD_ID )
2023-04-18 12:54:44 +03:00
reinit_completion ( & ctrl - > broadcast ) ;
2022-10-26 14:02:05 +03:00
2021-03-30 17:47:15 +03:00
/* Its assumed that write is okay as we do not get any status back */
2023-04-18 12:54:45 +03:00
ctrl - > reg_write ( ctrl , ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_WR_CMD ] , val ) ;
2021-03-30 17:47:15 +03:00
2023-04-18 12:54:44 +03:00
if ( ctrl - > version < = SWRM_VERSION_1_3_0 )
2021-03-30 17:47:15 +03:00
usleep_range ( 150 , 155 ) ;
if ( cmd_id = = SWR_BROADCAST_CMD_ID ) {
2023-05-25 16:38:10 +03:00
swrm_wait_for_wr_fifo_done ( ctrl ) ;
2021-03-30 17:47:15 +03:00
/*
* sleep for 10 ms for MSM soundwire variant to allow broadcast
* command to complete .
*/
2023-04-18 12:54:44 +03:00
ret = wait_for_completion_timeout ( & ctrl - > broadcast ,
2021-03-30 17:47:15 +03:00
msecs_to_jiffies ( TIMEOUT_MS ) ) ;
if ( ! ret )
ret = SDW_CMD_IGNORED ;
else
ret = SDW_CMD_OK ;
2020-01-13 16:21:53 +03:00
} else {
ret = SDW_CMD_OK ;
}
2021-03-30 17:47:15 +03:00
return ret ;
}
2020-01-13 16:21:53 +03:00
2023-04-18 12:54:44 +03:00
static int qcom_swrm_cmd_fifo_rd_cmd ( struct qcom_swrm_ctrl * ctrl ,
2021-03-30 17:47:15 +03:00
u8 dev_addr , u16 reg_addr ,
u32 len , u8 * rval )
{
u32 cmd_data , cmd_id , val , retry_attempt = 0 ;
2023-04-18 12:54:44 +03:00
val = swrm_get_packed_reg_val ( & ctrl - > rcmd_id , len , dev_addr , reg_addr ) ;
2021-03-30 17:47:15 +03:00
2022-10-26 14:02:06 +03:00
/*
* Check for outstanding cmd wrt . write fifo depth to avoid
* overflow as read will also increase write fifo cnt .
*/
2023-04-18 12:54:44 +03:00
swrm_wait_for_wr_fifo_avail ( ctrl ) ;
2022-10-26 14:02:06 +03:00
2021-03-30 17:47:15 +03:00
/* wait for FIFO RD to complete to avoid overflow */
usleep_range ( 100 , 105 ) ;
2023-04-18 12:54:45 +03:00
ctrl - > reg_write ( ctrl , ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_RD_CMD ] , val ) ;
2021-03-30 17:47:15 +03:00
/* wait for FIFO RD CMD complete to avoid overflow */
usleep_range ( 250 , 255 ) ;
2023-04-18 12:54:44 +03:00
if ( swrm_wait_for_rd_fifo_avail ( ctrl ) )
2021-04-01 12:00:58 +03:00
return SDW_CMD_FAIL_OTHER ;
2021-03-30 17:47:15 +03:00
do {
2023-04-18 12:54:45 +03:00
ctrl - > reg_read ( ctrl , ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_RD_FIFO_ADDR ] ,
& cmd_data ) ;
2021-03-30 17:47:15 +03:00
rval [ 0 ] = cmd_data & 0xFF ;
cmd_id = FIELD_GET ( SWRM_RD_FIFO_CMD_ID_MASK , cmd_data ) ;
2023-04-18 12:54:44 +03:00
if ( cmd_id ! = ctrl - > rcmd_id ) {
2021-03-30 17:47:15 +03:00
if ( retry_attempt < ( MAX_FIFO_RD_RETRY - 1 ) ) {
/* wait 500 us before retry on fifo read failure */
usleep_range ( 500 , 505 ) ;
2023-04-18 12:54:44 +03:00
ctrl - > reg_write ( ctrl , SWRM_CMD_FIFO_CMD ,
2021-03-30 17:47:15 +03:00
SWRM_CMD_FIFO_FLUSH ) ;
2023-04-18 12:54:45 +03:00
ctrl - > reg_write ( ctrl ,
ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_RD_CMD ] ,
val ) ;
2021-03-30 17:47:15 +03:00
}
retry_attempt + + ;
} else {
return SDW_CMD_OK ;
}
2020-01-13 16:21:53 +03:00
2021-03-30 17:47:15 +03:00
} while ( retry_attempt < MAX_FIFO_RD_RETRY ) ;
2020-01-13 16:21:53 +03:00
2023-04-18 12:54:44 +03:00
dev_err ( ctrl - > dev , " failed to read fifo: reg: 0x%x, rcmd_id: 0x%x, \
2021-03-30 17:47:15 +03:00
dev_num : 0 x % x , cmd_data : 0 x % x \ n " ,
2023-04-18 12:54:44 +03:00
reg_addr , ctrl - > rcmd_id , dev_addr , cmd_data ) ;
2021-03-30 17:47:15 +03:00
return SDW_CMD_IGNORED ;
2020-01-13 16:21:53 +03:00
}
2021-03-30 17:47:16 +03:00
static int qcom_swrm_get_alert_slave_dev_num ( struct qcom_swrm_ctrl * ctrl )
{
u32 val , status ;
int dev_num ;
ctrl - > reg_read ( ctrl , SWRM_MCP_SLV_STATUS , & val ) ;
2022-09-16 16:53:52 +03:00
for ( dev_num = 1 ; dev_num < = SDW_MAX_DEVICES ; dev_num + + ) {
2021-03-30 17:47:16 +03:00
status = ( val > > ( dev_num * SWRM_MCP_SLV_STATUS_SZ ) ) ;
if ( ( status & SWRM_MCP_SLV_STATUS_MASK ) = = SDW_SLAVE_ALERT ) {
2023-05-25 16:38:09 +03:00
ctrl - > status [ dev_num ] = status & SWRM_MCP_SLV_STATUS_MASK ;
2021-03-30 17:47:16 +03:00
return dev_num ;
}
}
return - EINVAL ;
}
2020-01-13 16:21:53 +03:00
static void qcom_swrm_get_device_status ( struct qcom_swrm_ctrl * ctrl )
{
u32 val ;
int i ;
ctrl - > reg_read ( ctrl , SWRM_MCP_SLV_STATUS , & val ) ;
2021-03-30 17:47:18 +03:00
ctrl - > slave_status = val ;
2020-01-13 16:21:53 +03:00
2022-09-16 16:53:51 +03:00
for ( i = 1 ; i < = SDW_MAX_DEVICES ; i + + ) {
2020-01-13 16:21:53 +03:00
u32 s ;
s = ( val > > ( i * 2 ) ) ;
s & = SWRM_MCP_SLV_STATUS_MASK ;
ctrl - > status [ i ] = s ;
}
}
2021-03-30 17:47:18 +03:00
static void qcom_swrm_set_slave_dev_num ( struct sdw_bus * bus ,
struct sdw_slave * slave , int devnum )
{
struct qcom_swrm_ctrl * ctrl = to_qcom_sdw ( bus ) ;
u32 status ;
ctrl - > reg_read ( ctrl , SWRM_MCP_SLV_STATUS , & status ) ;
status = ( status > > ( devnum * SWRM_MCP_SLV_STATUS_SZ ) ) ;
status & = SWRM_MCP_SLV_STATUS_MASK ;
if ( status = = SDW_SLAVE_ATTACHED ) {
if ( slave )
slave - > dev_num = devnum ;
mutex_lock ( & bus - > bus_lock ) ;
set_bit ( devnum , bus - > assigned ) ;
mutex_unlock ( & bus - > bus_lock ) ;
}
}
static int qcom_swrm_enumerate ( struct sdw_bus * bus )
{
struct qcom_swrm_ctrl * ctrl = to_qcom_sdw ( bus ) ;
struct sdw_slave * slave , * _s ;
struct sdw_slave_id id ;
u32 val1 , val2 ;
bool found ;
u64 addr ;
int i ;
char * buf1 = ( char * ) & val1 , * buf2 = ( char * ) & val2 ;
for ( i = 1 ; i < = SDW_MAX_DEVICES ; i + + ) {
2022-07-06 12:56:44 +03:00
/* do not continue if the status is Not Present */
if ( ! ctrl - > status [ i ] )
continue ;
2021-03-30 17:47:18 +03:00
/*SCP_Devid5 - Devid 4*/
ctrl - > reg_read ( ctrl , SWRM_ENUMERATOR_SLAVE_DEV_ID_1 ( i ) , & val1 ) ;
/*SCP_Devid3 - DevId 2 Devid 1 Devid 0*/
ctrl - > reg_read ( ctrl , SWRM_ENUMERATOR_SLAVE_DEV_ID_2 ( i ) , & val2 ) ;
if ( ! val1 & & ! val2 )
break ;
addr = buf2 [ 1 ] | ( buf2 [ 0 ] < < 8 ) | ( buf1 [ 3 ] < < 16 ) |
( ( u64 ) buf1 [ 2 ] < < 24 ) | ( ( u64 ) buf1 [ 1 ] < < 32 ) |
( ( u64 ) buf1 [ 0 ] < < 40 ) ;
sdw_extract_slave_id ( bus , addr , & id ) ;
found = false ;
2023-05-25 16:38:12 +03:00
ctrl - > clock_stop_not_supported = false ;
2021-03-30 17:47:18 +03:00
/* Now compare with entries */
list_for_each_entry_safe ( slave , _s , & bus - > slaves , node ) {
if ( sdw_compare_devid ( slave , id ) = = 0 ) {
qcom_swrm_set_slave_dev_num ( bus , slave , i ) ;
2023-05-25 16:38:12 +03:00
if ( slave - > prop . clk_stop_mode1 )
ctrl - > clock_stop_not_supported = true ;
2021-03-30 17:47:18 +03:00
found = true ;
break ;
}
}
if ( ! found ) {
qcom_swrm_set_slave_dev_num ( bus , NULL , i ) ;
sdw_slave_add ( bus , & id , NULL ) ;
}
}
2021-03-30 17:47:19 +03:00
complete ( & ctrl - > enumeration ) ;
2021-03-30 17:47:18 +03:00
return 0 ;
}
2022-02-28 20:25:28 +03:00
static irqreturn_t qcom_swrm_wake_irq_handler ( int irq , void * dev_id )
{
2023-04-18 12:54:44 +03:00
struct qcom_swrm_ctrl * ctrl = dev_id ;
2022-02-28 20:25:28 +03:00
int ret ;
2023-05-17 19:37:49 +03:00
ret = pm_runtime_get_sync ( ctrl - > dev ) ;
2022-02-28 20:25:28 +03:00
if ( ret < 0 & & ret ! = - EACCES ) {
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev ,
2023-05-17 19:37:49 +03:00
" pm_runtime_get_sync failed in %s, ret %d \n " ,
2022-02-28 20:25:28 +03:00
__func__ , ret ) ;
2023-05-17 19:37:49 +03:00
pm_runtime_put_noidle ( ctrl - > dev ) ;
2022-04-27 02:56:19 +03:00
return ret ;
2022-02-28 20:25:28 +03:00
}
2023-04-18 12:54:44 +03:00
if ( ctrl - > wake_irq > 0 ) {
if ( ! irqd_irq_disabled ( irq_get_irq_data ( ctrl - > wake_irq ) ) )
disable_irq_nosync ( ctrl - > wake_irq ) ;
2022-02-28 20:25:28 +03:00
}
2023-04-18 12:54:44 +03:00
pm_runtime_mark_last_busy ( ctrl - > dev ) ;
pm_runtime_put_autosuspend ( ctrl - > dev ) ;
2022-02-28 20:25:28 +03:00
return IRQ_HANDLED ;
}
2020-01-13 16:21:53 +03:00
static irqreturn_t qcom_swrm_irq_handler ( int irq , void * dev_id )
{
2023-04-18 12:54:44 +03:00
struct qcom_swrm_ctrl * ctrl = dev_id ;
2021-03-30 17:47:18 +03:00
u32 value , intr_sts , intr_sts_masked , slave_status ;
2021-03-30 17:47:16 +03:00
u32 i ;
2021-03-31 18:55:20 +03:00
int devnum ;
2021-03-30 17:47:16 +03:00
int ret = IRQ_HANDLED ;
2023-04-18 12:54:44 +03:00
clk_prepare_enable ( ctrl - > hclk ) ;
2020-01-13 16:21:53 +03:00
2023-04-18 12:54:45 +03:00
ctrl - > reg_read ( ctrl , ctrl - > reg_layout [ SWRM_REG_INTERRUPT_STATUS ] ,
& intr_sts ) ;
2023-04-18 12:54:44 +03:00
intr_sts_masked = intr_sts & ctrl - > intr_mask ;
2020-01-13 16:21:53 +03:00
2021-03-30 17:47:16 +03:00
do {
for ( i = 0 ; i < SWRM_INTERRUPT_MAX ; i + + ) {
value = intr_sts_masked & BIT ( i ) ;
if ( ! value )
continue ;
switch ( value ) {
case SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ :
2023-04-18 12:54:44 +03:00
devnum = qcom_swrm_get_alert_slave_dev_num ( ctrl ) ;
2021-03-30 17:47:16 +03:00
if ( devnum < 0 ) {
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev ,
2021-03-30 17:47:16 +03:00
" no slave alert found.spurious interrupt \n " ) ;
} else {
2023-04-18 12:54:44 +03:00
sdw_handle_slave_status ( & ctrl - > bus , ctrl - > status ) ;
2021-03-30 17:47:16 +03:00
}
break ;
case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED :
case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS :
2023-04-18 12:54:44 +03:00
dev_dbg_ratelimited ( ctrl - > dev , " SWR new slave attached \n " ) ;
ctrl - > reg_read ( ctrl , SWRM_MCP_SLV_STATUS , & slave_status ) ;
if ( ctrl - > slave_status = = slave_status ) {
dev_dbg ( ctrl - > dev , " Slave status not changed %x \n " ,
2021-03-30 17:47:18 +03:00
slave_status ) ;
} else {
2023-04-18 12:54:44 +03:00
qcom_swrm_get_device_status ( ctrl ) ;
qcom_swrm_enumerate ( & ctrl - > bus ) ;
sdw_handle_slave_status ( & ctrl - > bus , ctrl - > status ) ;
2021-03-30 17:47:18 +03:00
}
2021-03-30 17:47:16 +03:00
break ;
case SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET :
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev ,
2021-03-30 17:47:16 +03:00
" %s: SWR bus clsh detected \n " ,
__func__ ) ;
2023-04-18 12:54:44 +03:00
ctrl - > intr_mask & = ~ SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET ;
2023-04-18 12:54:45 +03:00
ctrl - > reg_write ( ctrl ,
ctrl - > reg_layout [ SWRM_REG_INTERRUPT_CPU_EN ] ,
ctrl - > intr_mask ) ;
2021-03-30 17:47:16 +03:00
break ;
case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW :
2023-04-18 12:54:45 +03:00
ctrl - > reg_read ( ctrl ,
ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_STATUS ] ,
& value ) ;
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev ,
2021-03-30 17:47:16 +03:00
" %s: SWR read FIFO overflow fifo status 0x%x \n " ,
__func__ , value ) ;
break ;
case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW :
2023-04-18 12:54:45 +03:00
ctrl - > reg_read ( ctrl ,
ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_STATUS ] ,
& value ) ;
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev ,
2021-03-30 17:47:16 +03:00
" %s: SWR read FIFO underflow fifo status 0x%x \n " ,
__func__ , value ) ;
break ;
case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW :
2023-04-18 12:54:45 +03:00
ctrl - > reg_read ( ctrl ,
ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_STATUS ] ,
& value ) ;
2023-04-18 12:54:44 +03:00
dev_err ( ctrl - > dev ,
2021-03-30 17:47:16 +03:00
" %s: SWR write FIFO overflow fifo status %x \n " ,
__func__ , value ) ;
2023-04-18 12:54:44 +03:00
ctrl - > reg_write ( ctrl , SWRM_CMD_FIFO_CMD , 0x1 ) ;
2021-03-30 17:47:16 +03:00
break ;
case SWRM_INTERRUPT_STATUS_CMD_ERROR :
2023-04-18 12:54:45 +03:00
ctrl - > reg_read ( ctrl ,
ctrl - > reg_layout [ SWRM_REG_CMD_FIFO_STATUS ] ,
& value ) ;
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev ,
2021-03-30 17:47:16 +03:00
" %s: SWR CMD error, fifo status 0x%x, flushing fifo \n " ,
__func__ , value ) ;
2023-04-18 12:54:44 +03:00
ctrl - > reg_write ( ctrl , SWRM_CMD_FIFO_CMD , 0x1 ) ;
2021-03-30 17:47:16 +03:00
break ;
case SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION :
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev ,
2021-03-30 17:47:16 +03:00
" %s: SWR Port collision detected \n " ,
__func__ ) ;
2023-04-18 12:54:44 +03:00
ctrl - > intr_mask & = ~ SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION ;
ctrl - > reg_write ( ctrl ,
2023-04-18 12:54:45 +03:00
ctrl - > reg_layout [ SWRM_REG_INTERRUPT_CPU_EN ] ,
ctrl - > intr_mask ) ;
2021-03-30 17:47:16 +03:00
break ;
case SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH :
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev ,
2021-03-30 17:47:16 +03:00
" %s: SWR read enable valid mismatch \n " ,
__func__ ) ;
2023-04-18 12:54:44 +03:00
ctrl - > intr_mask & =
2021-03-30 17:47:16 +03:00
~ SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH ;
2023-04-18 12:54:44 +03:00
ctrl - > reg_write ( ctrl ,
2023-04-18 12:54:45 +03:00
ctrl - > reg_layout [ SWRM_REG_INTERRUPT_CPU_EN ] ,
ctrl - > intr_mask ) ;
2021-03-30 17:47:16 +03:00
break ;
case SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED :
2023-04-18 12:54:44 +03:00
complete ( & ctrl - > broadcast ) ;
2021-03-30 17:47:16 +03:00
break ;
case SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2 :
break ;
case SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2 :
break ;
case SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP :
break ;
default :
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev ,
2021-03-30 17:47:16 +03:00
" %s: SWR unknown interrupt value: %d \n " ,
__func__ , value ) ;
ret = IRQ_NONE ;
break ;
}
}
2023-04-18 12:54:45 +03:00
ctrl - > reg_write ( ctrl , ctrl - > reg_layout [ SWRM_REG_INTERRUPT_CLEAR ] ,
intr_sts ) ;
ctrl - > reg_read ( ctrl , ctrl - > reg_layout [ SWRM_REG_INTERRUPT_STATUS ] ,
& intr_sts ) ;
2023-04-18 12:54:44 +03:00
intr_sts_masked = intr_sts & ctrl - > intr_mask ;
2021-03-30 17:47:16 +03:00
} while ( intr_sts_masked ) ;
2020-01-13 16:21:53 +03:00
2023-04-18 12:54:44 +03:00
clk_disable_unprepare ( ctrl - > hclk ) ;
2021-03-30 17:47:16 +03:00
return ret ;
2020-01-13 16:21:53 +03:00
}
2021-03-30 17:47:15 +03:00
2023-05-25 16:38:11 +03:00
static bool swrm_wait_for_frame_gen_enabled ( struct qcom_swrm_ctrl * ctrl )
{
int retry = SWRM_LINK_STATUS_RETRY_CNT ;
int comp_sts ;
do {
ctrl - > reg_read ( ctrl , SWRM_COMP_STATUS , & comp_sts ) ;
if ( comp_sts & SWRM_FRM_GEN_ENABLED )
return true ;
usleep_range ( 500 , 510 ) ;
} while ( retry - - ) ;
dev_err ( ctrl - > dev , " %s: link status not %s \n " , __func__ ,
comp_sts & SWRM_FRM_GEN_ENABLED ? " connected " : " disconnected " ) ;
return false ;
}
2020-01-13 16:21:53 +03:00
static int qcom_swrm_init ( struct qcom_swrm_ctrl * ctrl )
{
u32 val ;
/* Clear Rows and Cols */
2020-09-17 15:01:38 +03:00
val = FIELD_PREP ( SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK , ctrl - > rows_index ) ;
val | = FIELD_PREP ( SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK , ctrl - > cols_index ) ;
2020-01-13 16:21:53 +03:00
2022-05-18 15:42:35 +03:00
reset_control_reset ( ctrl - > audio_cgcr ) ;
2020-01-13 16:21:53 +03:00
ctrl - > reg_write ( ctrl , SWRM_MCP_FRAME_CTRL_BANK_ADDR ( 0 ) , val ) ;
2021-03-30 17:47:18 +03:00
/* Enable Auto enumeration */
ctrl - > reg_write ( ctrl , SWRM_ENUMERATOR_CFG_ADDR , 1 ) ;
2020-01-13 16:21:53 +03:00
2021-03-30 17:47:16 +03:00
ctrl - > intr_mask = SWRM_INTERRUPT_STATUS_RMSK ;
2020-01-13 16:21:53 +03:00
/* Mask soundwire interrupts */
2023-04-18 12:54:46 +03:00
if ( ctrl - > version < SWRM_VERSION_2_0_0 )
ctrl - > reg_write ( ctrl , ctrl - > reg_layout [ SWRM_REG_INTERRUPT_MASK_ADDR ] ,
SWRM_INTERRUPT_STATUS_RMSK ) ;
2020-01-13 16:21:53 +03:00
/* Configure No pings */
ctrl - > reg_read ( ctrl , SWRM_MCP_CFG_ADDR , & val ) ;
2020-09-17 15:01:36 +03:00
u32p_replace_bits ( & val , SWRM_DEF_CMD_NO_PINGS , SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK ) ;
2020-01-13 16:21:53 +03:00
ctrl - > reg_write ( ctrl , SWRM_MCP_CFG_ADDR , val ) ;
2023-04-18 12:54:46 +03:00
if ( ctrl - > version = = SWRM_VERSION_1_7_0 ) {
2022-10-26 14:02:10 +03:00
ctrl - > reg_write ( ctrl , SWRM_LINK_MANAGER_EE , SWRM_EE_CPU ) ;
ctrl - > reg_write ( ctrl , SWRM_MCP_BUS_CTRL ,
SWRM_MCP_BUS_CLK_START < < SWRM_EE_CPU ) ;
2023-04-18 12:54:46 +03:00
} else if ( ctrl - > version > = SWRM_VERSION_2_0_0 ) {
ctrl - > reg_write ( ctrl , SWRM_LINK_MANAGER_EE , SWRM_EE_CPU ) ;
ctrl - > reg_write ( ctrl , SWRM_V2_0_CLK_CTRL ,
SWRM_V2_0_CLK_CTRL_CLK_START ) ;
2022-10-26 14:02:10 +03:00
} else {
ctrl - > reg_write ( ctrl , SWRM_MCP_BUS_CTRL , SWRM_MCP_BUS_CLK_START ) ;
}
2020-01-13 16:21:53 +03:00
/* Configure number of retries of a read/write cmd */
2023-02-22 17:44:11 +03:00
if ( ctrl - > version > = SWRM_VERSION_1_5_1 ) {
2021-03-30 17:47:13 +03:00
ctrl - > reg_write ( ctrl , SWRM_CMD_FIFO_CFG_ADDR ,
SWRM_RD_WR_CMD_RETRIES |
SWRM_CONTINUE_EXEC_ON_CMD_IGNORE ) ;
} else {
ctrl - > reg_write ( ctrl , SWRM_CMD_FIFO_CFG_ADDR ,
SWRM_RD_WR_CMD_RETRIES ) ;
}
2020-01-13 16:21:53 +03:00
2023-05-25 16:38:11 +03:00
/* COMP Enable */
ctrl - > reg_write ( ctrl , SWRM_COMP_CFG_ADDR , SWRM_COMP_CFG_ENABLE_MSK ) ;
2020-01-13 16:21:53 +03:00
/* Set IRQ to PULSE */
ctrl - > reg_write ( ctrl , SWRM_COMP_CFG_ADDR ,
2023-05-25 16:38:11 +03:00
SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK ) ;
ctrl - > reg_write ( ctrl , ctrl - > reg_layout [ SWRM_REG_INTERRUPT_CLEAR ] ,
0xFFFFFFFF ) ;
2020-09-05 20:39:04 +03:00
/* enable CPU IRQs */
if ( ctrl - > mmio ) {
2023-04-18 12:54:45 +03:00
ctrl - > reg_write ( ctrl , ctrl - > reg_layout [ SWRM_REG_INTERRUPT_CPU_EN ] ,
2020-09-05 20:39:04 +03:00
SWRM_INTERRUPT_STATUS_RMSK ) ;
}
2023-05-25 16:38:11 +03:00
/* Set IRQ to PULSE */
ctrl - > reg_write ( ctrl , SWRM_COMP_CFG_ADDR ,
SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK |
SWRM_COMP_CFG_ENABLE_MSK ) ;
swrm_wait_for_frame_gen_enabled ( ctrl ) ;
2021-03-30 17:47:18 +03:00
ctrl - > slave_status = 0 ;
2021-04-01 12:00:58 +03:00
ctrl - > reg_read ( ctrl , SWRM_COMP_PARAMS , & val ) ;
ctrl - > rd_fifo_depth = FIELD_GET ( SWRM_COMP_PARAMS_RD_FIFO_DEPTH , val ) ;
ctrl - > wr_fifo_depth = FIELD_GET ( SWRM_COMP_PARAMS_WR_FIFO_DEPTH , val ) ;
2020-01-13 16:21:53 +03:00
return 0 ;
}
static enum sdw_command_response qcom_swrm_xfer_msg ( struct sdw_bus * bus ,
struct sdw_msg * msg )
{
struct qcom_swrm_ctrl * ctrl = to_qcom_sdw ( bus ) ;
int ret , i , len ;
if ( msg - > flags = = SDW_MSG_FLAG_READ ) {
for ( i = 0 ; i < msg - > len ; ) {
if ( ( msg - > len - i ) < QCOM_SWRM_MAX_RD_LEN )
len = msg - > len - i ;
else
len = QCOM_SWRM_MAX_RD_LEN ;
ret = qcom_swrm_cmd_fifo_rd_cmd ( ctrl , msg - > dev_num ,
msg - > addr + i , len ,
& msg - > buf [ i ] ) ;
if ( ret )
return ret ;
i = i + len ;
}
} else if ( msg - > flags = = SDW_MSG_FLAG_WRITE ) {
for ( i = 0 ; i < msg - > len ; i + + ) {
ret = qcom_swrm_cmd_fifo_wr_cmd ( ctrl , msg - > buf [ i ] ,
msg - > dev_num ,
msg - > addr + i ) ;
if ( ret )
return SDW_CMD_IGNORED ;
}
}
return SDW_CMD_OK ;
}
static int qcom_swrm_pre_bank_switch ( struct sdw_bus * bus )
{
u32 reg = SWRM_MCP_FRAME_CTRL_BANK_ADDR ( bus - > params . next_bank ) ;
struct qcom_swrm_ctrl * ctrl = to_qcom_sdw ( bus ) ;
u32 val ;
ctrl - > reg_read ( ctrl , reg , & val ) ;
2020-09-17 15:01:38 +03:00
u32p_replace_bits ( & val , ctrl - > cols_index , SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK ) ;
u32p_replace_bits ( & val , ctrl - > rows_index , SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK ) ;
2020-01-13 16:21:53 +03:00
return ctrl - > reg_write ( ctrl , reg , val ) ;
}
static int qcom_swrm_port_params ( struct sdw_bus * bus ,
struct sdw_port_params * p_params ,
unsigned int bank )
{
2021-03-30 17:47:12 +03:00
struct qcom_swrm_ctrl * ctrl = to_qcom_sdw ( bus ) ;
return ctrl - > reg_write ( ctrl , SWRM_DP_BLOCK_CTRL_1 ( p_params - > num ) ,
p_params - > bps - 1 ) ;
2020-01-13 16:21:53 +03:00
}
static int qcom_swrm_transport_params ( struct sdw_bus * bus ,
struct sdw_transport_params * params ,
enum sdw_reg_bank bank )
{
struct qcom_swrm_ctrl * ctrl = to_qcom_sdw ( bus ) ;
2021-03-30 17:47:12 +03:00
struct qcom_swrm_port_config * pcfg ;
2020-01-13 16:21:53 +03:00
u32 value ;
2020-09-17 15:01:37 +03:00
int reg = SWRM_DP_PORT_CTRL_BANK ( ( params - > port_num ) , bank ) ;
int ret ;
2020-01-13 16:21:53 +03:00
2021-04-01 12:24:54 +03:00
pcfg = & ctrl - > pconfig [ params - > port_num ] ;
2021-03-30 17:47:12 +03:00
value = pcfg - > off1 < < SWRM_DP_PORT_CTRL_OFFSET1_SHFT ;
value | = pcfg - > off2 < < SWRM_DP_PORT_CTRL_OFFSET2_SHFT ;
2023-04-18 12:54:43 +03:00
value | = pcfg - > si & 0xff ;
2020-01-13 16:21:53 +03:00
2020-09-17 15:01:37 +03:00
ret = ctrl - > reg_write ( ctrl , reg , value ) ;
2021-04-01 12:15:02 +03:00
if ( ret )
goto err ;
2020-09-17 15:01:37 +03:00
2023-04-18 12:54:43 +03:00
if ( pcfg - > si > 0xff ) {
value = ( pcfg - > si > > 8 ) & 0xff ;
reg = SWRM_DP_SAMPLECTRL2_BANK ( params - > port_num , bank ) ;
ret = ctrl - > reg_write ( ctrl , reg , value ) ;
if ( ret )
goto err ;
}
2021-03-30 17:47:12 +03:00
if ( pcfg - > lane_control ! = SWR_INVALID_PARAM ) {
reg = SWRM_DP_PORT_CTRL_2_BANK ( params - > port_num , bank ) ;
value = pcfg - > lane_control ;
ret = ctrl - > reg_write ( ctrl , reg , value ) ;
2021-04-01 12:15:02 +03:00
if ( ret )
goto err ;
2021-03-30 17:47:12 +03:00
}
2020-09-17 15:01:37 +03:00
2021-03-30 17:47:12 +03:00
if ( pcfg - > blk_group_count ! = SWR_INVALID_PARAM ) {
reg = SWRM_DP_BLOCK_CTRL2_BANK ( params - > port_num , bank ) ;
value = pcfg - > blk_group_count ;
ret = ctrl - > reg_write ( ctrl , reg , value ) ;
2021-04-01 12:15:02 +03:00
if ( ret )
goto err ;
2021-03-30 17:47:12 +03:00
}
if ( pcfg - > hstart ! = SWR_INVALID_PARAM
& & pcfg - > hstop ! = SWR_INVALID_PARAM ) {
reg = SWRM_DP_PORT_HCTRL_BANK ( params - > port_num , bank ) ;
value = ( pcfg - > hstop < < 4 ) | pcfg - > hstart ;
ret = ctrl - > reg_write ( ctrl , reg , value ) ;
} else {
reg = SWRM_DP_PORT_HCTRL_BANK ( params - > port_num , bank ) ;
value = ( SWR_HSTOP_MAX_VAL < < 4 ) | SWR_HSTART_MIN_VAL ;
ret = ctrl - > reg_write ( ctrl , reg , value ) ;
}
2021-04-01 12:15:02 +03:00
if ( ret )
goto err ;
2021-03-30 17:47:12 +03:00
if ( pcfg - > bp_mode ! = SWR_INVALID_PARAM ) {
reg = SWRM_DP_BLOCK_CTRL3_BANK ( params - > port_num , bank ) ;
ret = ctrl - > reg_write ( ctrl , reg , pcfg - > bp_mode ) ;
2020-09-17 15:01:37 +03:00
}
2021-04-01 12:15:02 +03:00
err :
2020-09-17 15:01:37 +03:00
return ret ;
2020-01-13 16:21:53 +03:00
}
static int qcom_swrm_port_enable ( struct sdw_bus * bus ,
struct sdw_enable_ch * enable_ch ,
unsigned int bank )
{
u32 reg = SWRM_DP_PORT_CTRL_BANK ( enable_ch - > port_num , bank ) ;
struct qcom_swrm_ctrl * ctrl = to_qcom_sdw ( bus ) ;
u32 val ;
ctrl - > reg_read ( ctrl , reg , & val ) ;
if ( enable_ch - > enable )
val | = ( enable_ch - > ch_mask < < SWRM_DP_PORT_CTRL_EN_CHAN_SHFT ) ;
else
val & = ~ ( 0xff < < SWRM_DP_PORT_CTRL_EN_CHAN_SHFT ) ;
return ctrl - > reg_write ( ctrl , reg , val ) ;
}
2020-06-10 02:00:29 +03:00
static const struct sdw_master_port_ops qcom_swrm_port_ops = {
2020-01-13 16:21:53 +03:00
. dpn_set_port_params = qcom_swrm_port_params ,
. dpn_set_port_transport_params = qcom_swrm_transport_params ,
. dpn_port_enable_ch = qcom_swrm_port_enable ,
} ;
2020-06-10 02:00:29 +03:00
static const struct sdw_master_ops qcom_swrm_ops = {
2020-01-13 16:21:53 +03:00
. xfer_msg = qcom_swrm_xfer_msg ,
. pre_bank_switch = qcom_swrm_pre_bank_switch ,
} ;
static int qcom_swrm_compute_params ( struct sdw_bus * bus )
{
struct qcom_swrm_ctrl * ctrl = to_qcom_sdw ( bus ) ;
struct sdw_master_runtime * m_rt ;
struct sdw_slave_runtime * s_rt ;
struct sdw_port_runtime * p_rt ;
struct qcom_swrm_port_config * pcfg ;
2021-03-15 19:56:48 +03:00
struct sdw_slave * slave ;
unsigned int m_port ;
2021-04-01 12:24:54 +03:00
int i = 1 ;
2020-01-13 16:21:53 +03:00
list_for_each_entry ( m_rt , & bus - > m_rt_list , bus_node ) {
list_for_each_entry ( p_rt , & m_rt - > port_list , port_node ) {
2021-04-01 12:24:54 +03:00
pcfg = & ctrl - > pconfig [ p_rt - > num ] ;
2020-01-13 16:21:53 +03:00
p_rt - > transport_params . port_num = p_rt - > num ;
2021-03-30 17:47:12 +03:00
if ( pcfg - > word_length ! = SWR_INVALID_PARAM ) {
sdw_fill_port_params ( & p_rt - > port_params ,
p_rt - > num , pcfg - > word_length + 1 ,
SDW_PORT_FLOW_MODE_ISOCH ,
SDW_PORT_DATA_MODE_NORMAL ) ;
}
2020-01-13 16:21:53 +03:00
}
list_for_each_entry ( s_rt , & m_rt - > slave_rt_list , m_rt_node ) {
2021-03-15 19:56:48 +03:00
slave = s_rt - > slave ;
2020-01-13 16:21:53 +03:00
list_for_each_entry ( p_rt , & s_rt - > port_list , port_node ) {
2021-03-15 19:56:48 +03:00
m_port = slave - > m_port_map [ p_rt - > num ] ;
/* port config starts at offset 0 so -1 from actual port number */
if ( m_port )
2021-04-01 12:24:54 +03:00
pcfg = & ctrl - > pconfig [ m_port ] ;
2021-03-15 19:56:48 +03:00
else
pcfg = & ctrl - > pconfig [ i ] ;
2020-01-13 16:21:53 +03:00
p_rt - > transport_params . port_num = p_rt - > num ;
p_rt - > transport_params . sample_interval =
pcfg - > si + 1 ;
p_rt - > transport_params . offset1 = pcfg - > off1 ;
p_rt - > transport_params . offset2 = pcfg - > off2 ;
2020-09-17 15:01:37 +03:00
p_rt - > transport_params . blk_pkg_mode = pcfg - > bp_mode ;
2021-03-30 17:47:12 +03:00
p_rt - > transport_params . blk_grp_ctrl = pcfg - > blk_group_count ;
p_rt - > transport_params . hstart = pcfg - > hstart ;
p_rt - > transport_params . hstop = pcfg - > hstop ;
p_rt - > transport_params . lane_ctrl = pcfg - > lane_control ;
if ( pcfg - > word_length ! = SWR_INVALID_PARAM ) {
sdw_fill_port_params ( & p_rt - > port_params ,
p_rt - > num ,
pcfg - > word_length + 1 ,
SDW_PORT_FLOW_MODE_ISOCH ,
SDW_PORT_DATA_MODE_NORMAL ) ;
}
2020-01-13 16:21:53 +03:00
i + + ;
}
}
}
return 0 ;
}
static u32 qcom_swrm_freq_tbl [ MAX_FREQ_NUM ] = {
DEFAULT_CLK_FREQ ,
} ;
static void qcom_swrm_stream_free_ports ( struct qcom_swrm_ctrl * ctrl ,
struct sdw_stream_runtime * stream )
{
struct sdw_master_runtime * m_rt ;
struct sdw_port_runtime * p_rt ;
unsigned long * port_mask ;
mutex_lock ( & ctrl - > port_lock ) ;
list_for_each_entry ( m_rt , & stream - > master_list , stream_node ) {
if ( m_rt - > direction = = SDW_DATA_DIR_RX )
port_mask = & ctrl - > dout_port_mask ;
else
port_mask = & ctrl - > din_port_mask ;
list_for_each_entry ( p_rt , & m_rt - > port_list , port_node )
2021-03-15 19:56:47 +03:00
clear_bit ( p_rt - > num , port_mask ) ;
2020-01-13 16:21:53 +03:00
}
mutex_unlock ( & ctrl - > port_lock ) ;
}
static int qcom_swrm_stream_alloc_ports ( struct qcom_swrm_ctrl * ctrl ,
struct sdw_stream_runtime * stream ,
struct snd_pcm_hw_params * params ,
int direction )
{
struct sdw_port_config pconfig [ QCOM_SDW_MAX_PORTS ] ;
struct sdw_stream_config sconfig ;
struct sdw_master_runtime * m_rt ;
struct sdw_slave_runtime * s_rt ;
struct sdw_port_runtime * p_rt ;
2021-03-15 19:56:48 +03:00
struct sdw_slave * slave ;
2020-01-13 16:21:53 +03:00
unsigned long * port_mask ;
int i , maxport , pn , nports = 0 , ret = 0 ;
2021-03-15 19:56:48 +03:00
unsigned int m_port ;
2020-01-13 16:21:53 +03:00
mutex_lock ( & ctrl - > port_lock ) ;
list_for_each_entry ( m_rt , & stream - > master_list , stream_node ) {
if ( m_rt - > direction = = SDW_DATA_DIR_RX ) {
maxport = ctrl - > num_dout_ports ;
port_mask = & ctrl - > dout_port_mask ;
} else {
maxport = ctrl - > num_din_ports ;
port_mask = & ctrl - > din_port_mask ;
}
list_for_each_entry ( s_rt , & m_rt - > slave_rt_list , m_rt_node ) {
2021-03-15 19:56:48 +03:00
slave = s_rt - > slave ;
2020-01-13 16:21:53 +03:00
list_for_each_entry ( p_rt , & s_rt - > port_list , port_node ) {
2021-03-15 19:56:48 +03:00
m_port = slave - > m_port_map [ p_rt - > num ] ;
2020-01-13 16:21:53 +03:00
/* Port numbers start from 1 - 14*/
2021-03-15 19:56:48 +03:00
if ( m_port )
pn = m_port ;
else
pn = find_first_zero_bit ( port_mask , maxport ) ;
2021-03-15 19:56:47 +03:00
if ( pn > maxport ) {
2020-01-13 16:21:53 +03:00
dev_err ( ctrl - > dev , " All ports busy \n " ) ;
ret = - EBUSY ;
goto err ;
}
set_bit ( pn , port_mask ) ;
2021-03-15 19:56:47 +03:00
pconfig [ nports ] . num = pn ;
2020-01-13 16:21:53 +03:00
pconfig [ nports ] . ch_mask = p_rt - > ch_mask ;
nports + + ;
}
}
}
if ( direction = = SNDRV_PCM_STREAM_CAPTURE )
sconfig . direction = SDW_DATA_DIR_TX ;
else
sconfig . direction = SDW_DATA_DIR_RX ;
/* hw parameters wil be ignored as we only support PDM */
sconfig . ch_count = 1 ;
sconfig . frame_rate = params_rate ( params ) ;
sconfig . type = stream - > type ;
sconfig . bps = 1 ;
sdw_stream_add_master ( & ctrl - > bus , & sconfig , pconfig ,
nports , stream ) ;
err :
if ( ret ) {
for ( i = 0 ; i < nports ; i + + )
2021-03-15 19:56:47 +03:00
clear_bit ( pconfig [ i ] . num , port_mask ) ;
2020-01-13 16:21:53 +03:00
}
mutex_unlock ( & ctrl - > port_lock ) ;
return ret ;
}
static int qcom_swrm_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
struct qcom_swrm_ctrl * ctrl = dev_get_drvdata ( dai - > dev ) ;
struct sdw_stream_runtime * sruntime = ctrl - > sruntime [ dai - > id ] ;
int ret ;
ret = qcom_swrm_stream_alloc_ports ( ctrl , sruntime , params ,
substream - > stream ) ;
if ( ret )
qcom_swrm_stream_free_ports ( ctrl , sruntime ) ;
return ret ;
}
static int qcom_swrm_hw_free ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
struct qcom_swrm_ctrl * ctrl = dev_get_drvdata ( dai - > dev ) ;
struct sdw_stream_runtime * sruntime = ctrl - > sruntime [ dai - > id ] ;
qcom_swrm_stream_free_ports ( ctrl , sruntime ) ;
sdw_stream_remove_master ( & ctrl - > bus , sruntime ) ;
return 0 ;
}
static int qcom_swrm_set_sdw_stream ( struct snd_soc_dai * dai ,
void * stream , int direction )
{
struct qcom_swrm_ctrl * ctrl = dev_get_drvdata ( dai - > dev ) ;
ctrl - > sruntime [ dai - > id ] = stream ;
return 0 ;
}
2020-03-17 12:26:45 +03:00
static void * qcom_swrm_get_sdw_stream ( struct snd_soc_dai * dai , int direction )
{
struct qcom_swrm_ctrl * ctrl = dev_get_drvdata ( dai - > dev ) ;
return ctrl - > sruntime [ dai - > id ] ;
}
2020-01-13 16:21:53 +03:00
static int qcom_swrm_startup ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
struct qcom_swrm_ctrl * ctrl = dev_get_drvdata ( dai - > dev ) ;
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct sdw_stream_runtime * sruntime ;
2020-02-19 09:55:53 +03:00
struct snd_soc_dai * codec_dai ;
2020-01-13 16:21:53 +03:00
int ret , i ;
2023-05-17 19:37:49 +03:00
ret = pm_runtime_get_sync ( ctrl - > dev ) ;
2022-02-28 20:25:26 +03:00
if ( ret < 0 & & ret ! = - EACCES ) {
dev_err_ratelimited ( ctrl - > dev ,
2023-05-17 19:37:49 +03:00
" pm_runtime_get_sync failed in %s, ret %d \n " ,
2022-02-28 20:25:26 +03:00
__func__ , ret ) ;
2023-05-17 19:37:49 +03:00
pm_runtime_put_noidle ( ctrl - > dev ) ;
2022-02-28 20:25:26 +03:00
return ret ;
}
2020-01-13 16:21:53 +03:00
sruntime = sdw_alloc_stream ( dai - > name ) ;
2023-05-17 19:37:36 +03:00
if ( ! sruntime ) {
ret = - ENOMEM ;
goto err_alloc ;
}
2020-01-13 16:21:53 +03:00
ctrl - > sruntime [ dai - > id ] = sruntime ;
2020-03-09 07:07:57 +03:00
for_each_rtd_codec_dais ( rtd , i , codec_dai ) {
2021-12-24 05:10:31 +03:00
ret = snd_soc_dai_set_stream ( codec_dai , sruntime ,
substream - > stream ) ;
2020-01-13 16:21:53 +03:00
if ( ret < 0 & & ret ! = - ENOTSUPP ) {
2021-03-23 03:58:55 +03:00
dev_err ( dai - > dev , " Failed to set sdw stream on %s \n " ,
2020-02-19 09:55:53 +03:00
codec_dai - > name ) ;
2023-05-17 19:37:36 +03:00
goto err_set_stream ;
2020-01-13 16:21:53 +03:00
}
}
return 0 ;
2023-05-17 19:37:36 +03:00
err_set_stream :
sdw_release_stream ( sruntime ) ;
err_alloc :
pm_runtime_mark_last_busy ( ctrl - > dev ) ;
pm_runtime_put_autosuspend ( ctrl - > dev ) ;
return ret ;
2020-01-13 16:21:53 +03:00
}
static void qcom_swrm_shutdown ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
struct qcom_swrm_ctrl * ctrl = dev_get_drvdata ( dai - > dev ) ;
2023-05-25 16:38:10 +03:00
swrm_wait_for_wr_fifo_done ( ctrl ) ;
2020-01-13 16:21:53 +03:00
sdw_release_stream ( ctrl - > sruntime [ dai - > id ] ) ;
ctrl - > sruntime [ dai - > id ] = NULL ;
2022-02-28 20:25:26 +03:00
pm_runtime_mark_last_busy ( ctrl - > dev ) ;
pm_runtime_put_autosuspend ( ctrl - > dev ) ;
2020-01-13 16:21:53 +03:00
}
static const struct snd_soc_dai_ops qcom_swrm_pdm_dai_ops = {
. hw_params = qcom_swrm_hw_params ,
. hw_free = qcom_swrm_hw_free ,
. startup = qcom_swrm_startup ,
. shutdown = qcom_swrm_shutdown ,
2021-12-24 05:10:31 +03:00
. set_stream = qcom_swrm_set_sdw_stream ,
. get_stream = qcom_swrm_get_sdw_stream ,
2020-01-13 16:21:53 +03:00
} ;
static const struct snd_soc_component_driver qcom_swrm_dai_component = {
. name = " soundwire " ,
} ;
static int qcom_swrm_register_dais ( struct qcom_swrm_ctrl * ctrl )
{
int num_dais = ctrl - > num_dout_ports + ctrl - > num_din_ports ;
struct snd_soc_dai_driver * dais ;
struct snd_soc_pcm_stream * stream ;
struct device * dev = ctrl - > dev ;
int i ;
/* PDM dais are only tested for now */
dais = devm_kcalloc ( dev , num_dais , sizeof ( * dais ) , GFP_KERNEL ) ;
if ( ! dais )
return - ENOMEM ;
for ( i = 0 ; i < num_dais ; i + + ) {
dais [ i ] . name = devm_kasprintf ( dev , GFP_KERNEL , " SDW Pin%d " , i ) ;
if ( ! dais [ i ] . name )
return - ENOMEM ;
if ( i < ctrl - > num_dout_ports )
stream = & dais [ i ] . playback ;
else
stream = & dais [ i ] . capture ;
stream - > channels_min = 1 ;
stream - > channels_max = 1 ;
stream - > rates = SNDRV_PCM_RATE_48000 ;
stream - > formats = SNDRV_PCM_FMTBIT_S16_LE ;
dais [ i ] . ops = & qcom_swrm_pdm_dai_ops ;
dais [ i ] . id = i ;
}
return devm_snd_soc_register_component ( ctrl - > dev ,
& qcom_swrm_dai_component ,
dais , num_dais ) ;
}
static int qcom_swrm_get_port_config ( struct qcom_swrm_ctrl * ctrl )
{
struct device_node * np = ctrl - > dev - > of_node ;
u8 off1 [ QCOM_SDW_MAX_PORTS ] ;
u8 off2 [ QCOM_SDW_MAX_PORTS ] ;
2023-04-18 12:54:43 +03:00
u16 si [ QCOM_SDW_MAX_PORTS ] ;
2020-09-17 15:01:37 +03:00
u8 bp_mode [ QCOM_SDW_MAX_PORTS ] = { 0 , } ;
2021-03-30 17:47:12 +03:00
u8 hstart [ QCOM_SDW_MAX_PORTS ] ;
u8 hstop [ QCOM_SDW_MAX_PORTS ] ;
u8 word_length [ QCOM_SDW_MAX_PORTS ] ;
u8 blk_group_count [ QCOM_SDW_MAX_PORTS ] ;
u8 lane_control [ QCOM_SDW_MAX_PORTS ] ;
2020-01-13 16:21:53 +03:00
int i , ret , nports , val ;
2023-04-18 12:54:43 +03:00
bool si_16 = false ;
2020-01-13 16:21:53 +03:00
ctrl - > reg_read ( ctrl , SWRM_COMP_PARAMS , & val ) ;
2020-09-03 14:45:00 +03:00
ctrl - > num_dout_ports = FIELD_GET ( SWRM_COMP_PARAMS_DOUT_PORTS_MASK , val ) ;
ctrl - > num_din_ports = FIELD_GET ( SWRM_COMP_PARAMS_DIN_PORTS_MASK , val ) ;
2020-01-13 16:21:53 +03:00
ret = of_property_read_u32 ( np , " qcom,din-ports " , & val ) ;
if ( ret )
return ret ;
if ( val > ctrl - > num_din_ports )
return - EINVAL ;
ctrl - > num_din_ports = val ;
ret = of_property_read_u32 ( np , " qcom,dout-ports " , & val ) ;
if ( ret )
return ret ;
if ( val > ctrl - > num_dout_ports )
return - EINVAL ;
ctrl - > num_dout_ports = val ;
nports = ctrl - > num_dout_ports + ctrl - > num_din_ports ;
2023-02-22 17:44:12 +03:00
if ( nports > QCOM_SDW_MAX_PORTS )
return - EINVAL ;
2021-03-15 19:56:47 +03:00
/* Valid port numbers are from 1-14, so mask out port 0 explicitly */
set_bit ( 0 , & ctrl - > dout_port_mask ) ;
set_bit ( 0 , & ctrl - > din_port_mask ) ;
2020-01-13 16:21:53 +03:00
ret = of_property_read_u8_array ( np , " qcom,ports-offset1 " ,
off1 , nports ) ;
if ( ret )
return ret ;
ret = of_property_read_u8_array ( np , " qcom,ports-offset2 " ,
off2 , nports ) ;
if ( ret )
return ret ;
ret = of_property_read_u8_array ( np , " qcom,ports-sinterval-low " ,
2023-04-18 12:54:43 +03:00
( u8 * ) si , nports ) ;
if ( ret ) {
ret = of_property_read_u16_array ( np , " qcom,ports-sinterval " ,
si , nports ) ;
if ( ret )
return ret ;
si_16 = true ;
}
2020-01-13 16:21:53 +03:00
2020-09-17 15:01:37 +03:00
ret = of_property_read_u8_array ( np , " qcom,ports-block-pack-mode " ,
bp_mode , nports ) ;
2021-05-04 15:59:09 +03:00
if ( ret ) {
2023-02-22 17:44:11 +03:00
if ( ctrl - > version < = SWRM_VERSION_1_3_0 )
2021-05-04 15:59:09 +03:00
memset ( bp_mode , SWR_INVALID_PARAM , QCOM_SDW_MAX_PORTS ) ;
else
return ret ;
}
2021-03-02 12:11:20 +03:00
2021-03-30 17:47:12 +03:00
memset ( hstart , SWR_INVALID_PARAM , QCOM_SDW_MAX_PORTS ) ;
of_property_read_u8_array ( np , " qcom,ports-hstart " , hstart , nports ) ;
memset ( hstop , SWR_INVALID_PARAM , QCOM_SDW_MAX_PORTS ) ;
of_property_read_u8_array ( np , " qcom,ports-hstop " , hstop , nports ) ;
memset ( word_length , SWR_INVALID_PARAM , QCOM_SDW_MAX_PORTS ) ;
of_property_read_u8_array ( np , " qcom,ports-word-length " , word_length , nports ) ;
memset ( blk_group_count , SWR_INVALID_PARAM , QCOM_SDW_MAX_PORTS ) ;
of_property_read_u8_array ( np , " qcom,ports-block-group-count " , blk_group_count , nports ) ;
memset ( lane_control , SWR_INVALID_PARAM , QCOM_SDW_MAX_PORTS ) ;
of_property_read_u8_array ( np , " qcom,ports-lane-control " , lane_control , nports ) ;
2020-01-13 16:21:53 +03:00
for ( i = 0 ; i < nports ; i + + ) {
2021-04-01 12:24:54 +03:00
/* Valid port number range is from 1-14 */
2023-04-18 12:54:43 +03:00
if ( si_16 )
ctrl - > pconfig [ i + 1 ] . si = si [ i ] ;
else
ctrl - > pconfig [ i + 1 ] . si = ( ( u8 * ) si ) [ i ] ;
2021-04-01 12:24:54 +03:00
ctrl - > pconfig [ i + 1 ] . off1 = off1 [ i ] ;
ctrl - > pconfig [ i + 1 ] . off2 = off2 [ i ] ;
ctrl - > pconfig [ i + 1 ] . bp_mode = bp_mode [ i ] ;
ctrl - > pconfig [ i + 1 ] . hstart = hstart [ i ] ;
ctrl - > pconfig [ i + 1 ] . hstop = hstop [ i ] ;
ctrl - > pconfig [ i + 1 ] . word_length = word_length [ i ] ;
ctrl - > pconfig [ i + 1 ] . blk_group_count = blk_group_count [ i ] ;
ctrl - > pconfig [ i + 1 ] . lane_control = lane_control [ i ] ;
2020-01-13 16:21:53 +03:00
}
return 0 ;
}
2021-09-07 13:56:36 +03:00
# ifdef CONFIG_DEBUG_FS
static int swrm_reg_show ( struct seq_file * s_file , void * data )
{
2023-04-18 12:54:44 +03:00
struct qcom_swrm_ctrl * ctrl = s_file - > private ;
2022-02-28 20:25:26 +03:00
int reg , reg_val , ret ;
2023-05-17 19:37:49 +03:00
ret = pm_runtime_get_sync ( ctrl - > dev ) ;
2022-02-28 20:25:26 +03:00
if ( ret < 0 & & ret ! = - EACCES ) {
2023-04-18 12:54:44 +03:00
dev_err_ratelimited ( ctrl - > dev ,
2023-05-17 19:37:49 +03:00
" pm_runtime_get_sync failed in %s, ret %d \n " ,
2022-02-28 20:25:26 +03:00
__func__ , ret ) ;
2023-05-17 19:37:49 +03:00
pm_runtime_put_noidle ( ctrl - > dev ) ;
2022-04-27 02:56:19 +03:00
return ret ;
2022-02-28 20:25:26 +03:00
}
2021-09-07 13:56:36 +03:00
2023-04-18 12:54:45 +03:00
for ( reg = 0 ; reg < = ctrl - > max_reg ; reg + = 4 ) {
2023-04-18 12:54:44 +03:00
ctrl - > reg_read ( ctrl , reg , & reg_val ) ;
2021-09-07 13:56:36 +03:00
seq_printf ( s_file , " 0x%.3x: 0x%.2x \n " , reg , reg_val ) ;
}
2023-04-18 12:54:44 +03:00
pm_runtime_mark_last_busy ( ctrl - > dev ) ;
pm_runtime_put_autosuspend ( ctrl - > dev ) ;
2022-02-28 20:25:26 +03:00
2021-09-07 13:56:36 +03:00
return 0 ;
}
DEFINE_SHOW_ATTRIBUTE ( swrm_reg ) ;
# endif
2020-01-13 16:21:53 +03:00
static int qcom_swrm_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct sdw_master_prop * prop ;
struct sdw_bus_params * params ;
struct qcom_swrm_ctrl * ctrl ;
2020-09-17 15:01:38 +03:00
const struct qcom_swrm_data * data ;
2020-01-13 16:21:53 +03:00
int ret ;
u32 val ;
ctrl = devm_kzalloc ( dev , sizeof ( * ctrl ) , GFP_KERNEL ) ;
if ( ! ctrl )
return - ENOMEM ;
2020-09-17 15:01:38 +03:00
data = of_device_get_match_data ( dev ) ;
2023-04-18 12:54:45 +03:00
ctrl - > max_reg = data - > max_reg ;
ctrl - > reg_layout = data - > reg_layout ;
2020-09-17 15:01:38 +03:00
ctrl - > rows_index = sdw_find_row_index ( data - > default_rows ) ;
ctrl - > cols_index = sdw_find_col_index ( data - > default_cols ) ;
2020-11-25 08:51:55 +03:00
# if IS_REACHABLE(CONFIG_SLIMBUS)
2020-01-13 16:21:53 +03:00
if ( dev - > parent - > bus = = & slimbus_bus ) {
2020-09-05 20:39:03 +03:00
# else
if ( false ) {
# endif
2020-09-05 20:39:02 +03:00
ctrl - > reg_read = qcom_swrm_ahb_reg_read ;
2020-01-13 16:21:53 +03:00
ctrl - > reg_write = qcom_swrm_ahb_reg_write ;
ctrl - > regmap = dev_get_regmap ( dev - > parent , NULL ) ;
if ( ! ctrl - > regmap )
return - EINVAL ;
} else {
2020-09-05 20:39:04 +03:00
ctrl - > reg_read = qcom_swrm_cpu_reg_read ;
ctrl - > reg_write = qcom_swrm_cpu_reg_write ;
ctrl - > mmio = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( ctrl - > mmio ) )
return PTR_ERR ( ctrl - > mmio ) ;
2020-01-13 16:21:53 +03:00
}
2022-07-01 10:17:06 +03:00
if ( data - > sw_clk_gate_required ) {
2022-10-26 14:02:08 +03:00
ctrl - > audio_cgcr = devm_reset_control_get_optional_exclusive ( dev , " swr_audio_cgcr " ) ;
if ( IS_ERR ( ctrl - > audio_cgcr ) ) {
2022-07-01 10:17:06 +03:00
dev_err ( dev , " Failed to get cgcr reset ctrl required for SW gating \n " ) ;
ret = PTR_ERR ( ctrl - > audio_cgcr ) ;
goto err_init ;
}
}
2020-01-13 16:21:53 +03:00
ctrl - > irq = of_irq_get ( dev - > of_node , 0 ) ;
2020-04-29 21:50:57 +03:00
if ( ctrl - > irq < 0 ) {
ret = ctrl - > irq ;
goto err_init ;
}
2020-01-13 16:21:53 +03:00
ctrl - > hclk = devm_clk_get ( dev , " iface " ) ;
2020-04-29 21:50:57 +03:00
if ( IS_ERR ( ctrl - > hclk ) ) {
ret = PTR_ERR ( ctrl - > hclk ) ;
goto err_init ;
}
2020-01-13 16:21:53 +03:00
clk_prepare_enable ( ctrl - > hclk ) ;
ctrl - > dev = dev ;
dev_set_drvdata ( & pdev - > dev , ctrl ) ;
mutex_init ( & ctrl - > port_lock ) ;
2021-03-30 17:47:15 +03:00
init_completion ( & ctrl - > broadcast ) ;
2021-03-30 17:47:19 +03:00
init_completion ( & ctrl - > enumeration ) ;
2020-01-13 16:21:53 +03:00
ctrl - > bus . ops = & qcom_swrm_ops ;
ctrl - > bus . port_ops = & qcom_swrm_port_ops ;
ctrl - > bus . compute_params = & qcom_swrm_compute_params ;
2022-02-28 20:25:26 +03:00
ctrl - > bus . clk_stop_timeout = 300 ;
2020-01-13 16:21:53 +03:00
ret = qcom_swrm_get_port_config ( ctrl ) ;
if ( ret )
2020-04-29 21:50:57 +03:00
goto err_clk ;
2020-01-13 16:21:53 +03:00
params = & ctrl - > bus . params ;
params - > max_dr_freq = DEFAULT_CLK_FREQ ;
params - > curr_dr_freq = DEFAULT_CLK_FREQ ;
2020-09-17 15:01:38 +03:00
params - > col = data - > default_cols ;
params - > row = data - > default_rows ;
2020-01-13 16:21:53 +03:00
ctrl - > reg_read ( ctrl , SWRM_MCP_STATUS , & val ) ;
params - > curr_bank = val & SWRM_MCP_STATUS_BANK_NUM_MASK ;
params - > next_bank = ! params - > curr_bank ;
prop = & ctrl - > bus . prop ;
prop - > max_clk_freq = DEFAULT_CLK_FREQ ;
prop - > num_clk_gears = 0 ;
prop - > num_clk_freq = MAX_FREQ_NUM ;
prop - > clk_freq = & qcom_swrm_freq_tbl [ 0 ] ;
2020-09-17 15:01:38 +03:00
prop - > default_col = data - > default_cols ;
prop - > default_row = data - > default_rows ;
2020-01-13 16:21:53 +03:00
ctrl - > reg_read ( ctrl , SWRM_COMP_HW_VERSION , & ctrl - > version ) ;
ret = devm_request_threaded_irq ( dev , ctrl - > irq , NULL ,
qcom_swrm_irq_handler ,
2020-05-06 06:25:53 +03:00
IRQF_TRIGGER_RISING |
IRQF_ONESHOT ,
2020-01-13 16:21:53 +03:00
" soundwire " , ctrl ) ;
if ( ret ) {
dev_err ( dev , " Failed to request soundwire irq \n " ) ;
2020-04-29 21:50:57 +03:00
goto err_clk ;
2020-01-13 16:21:53 +03:00
}
2022-02-28 20:25:28 +03:00
ctrl - > wake_irq = of_irq_get ( dev - > of_node , 1 ) ;
if ( ctrl - > wake_irq > 0 ) {
ret = devm_request_threaded_irq ( dev , ctrl - > wake_irq , NULL ,
qcom_swrm_wake_irq_handler ,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT ,
" swr_wake_irq " , ctrl ) ;
if ( ret ) {
dev_err ( dev , " Failed to request soundwire wake irq \n " ) ;
goto err_init ;
}
}
2020-05-18 20:43:18 +03:00
ret = sdw_bus_master_add ( & ctrl - > bus , dev , dev - > fwnode ) ;
2020-01-13 16:21:53 +03:00
if ( ret ) {
dev_err ( dev , " Failed to register Soundwire controller (%d) \n " ,
ret ) ;
2020-04-29 21:50:57 +03:00
goto err_clk ;
2020-01-13 16:21:53 +03:00
}
qcom_swrm_init ( ctrl ) ;
2021-03-30 17:47:19 +03:00
wait_for_completion_timeout ( & ctrl - > enumeration ,
msecs_to_jiffies ( TIMEOUT_MS ) ) ;
2020-01-13 16:21:53 +03:00
ret = qcom_swrm_register_dais ( ctrl ) ;
if ( ret )
2020-04-29 21:50:57 +03:00
goto err_master_add ;
2020-01-13 16:21:53 +03:00
dev_info ( dev , " Qualcomm Soundwire controller v%x.%x.%x Registered \n " ,
( ctrl - > version > > 24 ) & 0xff , ( ctrl - > version > > 16 ) & 0xff ,
ctrl - > version & 0xffff ) ;
2022-02-28 20:25:26 +03:00
pm_runtime_set_autosuspend_delay ( dev , 3000 ) ;
pm_runtime_use_autosuspend ( dev ) ;
pm_runtime_mark_last_busy ( dev ) ;
pm_runtime_set_active ( dev ) ;
pm_runtime_enable ( dev ) ;
2021-09-07 13:56:36 +03:00
# ifdef CONFIG_DEBUG_FS
ctrl - > debugfs = debugfs_create_dir ( " qualcomm-sdw " , ctrl - > bus . debugfs ) ;
debugfs_create_file ( " qualcomm-registers " , 0400 , ctrl - > debugfs , ctrl ,
& swrm_reg_fops ) ;
# endif
2020-01-13 16:21:53 +03:00
return 0 ;
2020-04-29 21:50:57 +03:00
err_master_add :
2020-05-18 20:43:18 +03:00
sdw_bus_master_delete ( & ctrl - > bus ) ;
2020-04-29 21:50:57 +03:00
err_clk :
2020-01-13 16:21:53 +03:00
clk_disable_unprepare ( ctrl - > hclk ) ;
2020-04-29 21:50:57 +03:00
err_init :
2020-01-13 16:21:53 +03:00
return ret ;
}
static int qcom_swrm_remove ( struct platform_device * pdev )
{
struct qcom_swrm_ctrl * ctrl = dev_get_drvdata ( & pdev - > dev ) ;
2020-05-18 20:43:18 +03:00
sdw_bus_master_delete ( & ctrl - > bus ) ;
2020-01-13 16:21:53 +03:00
clk_disable_unprepare ( ctrl - > hclk ) ;
return 0 ;
}
2022-03-03 14:03:21 +03:00
static int __maybe_unused swrm_runtime_resume ( struct device * dev )
2022-02-28 20:25:26 +03:00
{
struct qcom_swrm_ctrl * ctrl = dev_get_drvdata ( dev ) ;
int ret ;
2022-02-28 20:25:28 +03:00
if ( ctrl - > wake_irq > 0 ) {
if ( ! irqd_irq_disabled ( irq_get_irq_data ( ctrl - > wake_irq ) ) )
disable_irq_nosync ( ctrl - > wake_irq ) ;
}
2022-02-28 20:25:26 +03:00
clk_prepare_enable ( ctrl - > hclk ) ;
if ( ctrl - > clock_stop_not_supported ) {
reinit_completion ( & ctrl - > enumeration ) ;
ctrl - > reg_write ( ctrl , SWRM_COMP_SW_RESET , 0x01 ) ;
usleep_range ( 100 , 105 ) ;
qcom_swrm_init ( ctrl ) ;
usleep_range ( 100 , 105 ) ;
if ( ! swrm_wait_for_frame_gen_enabled ( ctrl ) )
dev_err ( ctrl - > dev , " link failed to connect \n " ) ;
/* wait for hw enumeration to complete */
wait_for_completion_timeout ( & ctrl - > enumeration ,
msecs_to_jiffies ( TIMEOUT_MS ) ) ;
qcom_swrm_get_device_status ( ctrl ) ;
sdw_handle_slave_status ( & ctrl - > bus , ctrl - > status ) ;
} else {
2022-05-18 15:42:35 +03:00
reset_control_reset ( ctrl - > audio_cgcr ) ;
2023-04-18 12:54:46 +03:00
if ( ctrl - > version = = SWRM_VERSION_1_7_0 ) {
2022-10-26 14:02:10 +03:00
ctrl - > reg_write ( ctrl , SWRM_LINK_MANAGER_EE , SWRM_EE_CPU ) ;
ctrl - > reg_write ( ctrl , SWRM_MCP_BUS_CTRL ,
SWRM_MCP_BUS_CLK_START < < SWRM_EE_CPU ) ;
2023-04-18 12:54:46 +03:00
} else if ( ctrl - > version > = SWRM_VERSION_2_0_0 ) {
ctrl - > reg_write ( ctrl , SWRM_LINK_MANAGER_EE , SWRM_EE_CPU ) ;
ctrl - > reg_write ( ctrl , SWRM_V2_0_CLK_CTRL ,
SWRM_V2_0_CLK_CTRL_CLK_START ) ;
2022-10-26 14:02:10 +03:00
} else {
ctrl - > reg_write ( ctrl , SWRM_MCP_BUS_CTRL , SWRM_MCP_BUS_CLK_START ) ;
}
2023-04-18 12:54:45 +03:00
ctrl - > reg_write ( ctrl , ctrl - > reg_layout [ SWRM_REG_INTERRUPT_CLEAR ] ,
2022-02-28 20:25:26 +03:00
SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET ) ;
ctrl - > intr_mask | = SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET ;
2023-04-18 12:54:46 +03:00
if ( ctrl - > version < SWRM_VERSION_2_0_0 )
ctrl - > reg_write ( ctrl ,
ctrl - > reg_layout [ SWRM_REG_INTERRUPT_MASK_ADDR ] ,
ctrl - > intr_mask ) ;
2023-04-18 12:54:45 +03:00
ctrl - > reg_write ( ctrl , ctrl - > reg_layout [ SWRM_REG_INTERRUPT_CPU_EN ] ,
ctrl - > intr_mask ) ;
2022-02-28 20:25:26 +03:00
usleep_range ( 100 , 105 ) ;
if ( ! swrm_wait_for_frame_gen_enabled ( ctrl ) )
dev_err ( ctrl - > dev , " link failed to connect \n " ) ;
ret = sdw_bus_exit_clk_stop ( & ctrl - > bus ) ;
if ( ret < 0 )
dev_err ( ctrl - > dev , " bus failed to exit clock stop %d \n " , ret ) ;
}
return 0 ;
}
static int __maybe_unused swrm_runtime_suspend ( struct device * dev )
{
struct qcom_swrm_ctrl * ctrl = dev_get_drvdata ( dev ) ;
int ret ;
2023-05-25 16:38:10 +03:00
swrm_wait_for_wr_fifo_done ( ctrl ) ;
2022-02-28 20:25:26 +03:00
if ( ! ctrl - > clock_stop_not_supported ) {
/* Mask bus clash interrupt */
ctrl - > intr_mask & = ~ SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET ;
2023-04-18 12:54:46 +03:00
if ( ctrl - > version < SWRM_VERSION_2_0_0 )
ctrl - > reg_write ( ctrl ,
ctrl - > reg_layout [ SWRM_REG_INTERRUPT_MASK_ADDR ] ,
ctrl - > intr_mask ) ;
2023-04-18 12:54:45 +03:00
ctrl - > reg_write ( ctrl , ctrl - > reg_layout [ SWRM_REG_INTERRUPT_CPU_EN ] ,
ctrl - > intr_mask ) ;
2022-02-28 20:25:26 +03:00
/* Prepare slaves for clock stop */
ret = sdw_bus_prep_clk_stop ( & ctrl - > bus ) ;
if ( ret < 0 & & ret ! = - ENODATA ) {
dev_err ( dev , " prepare clock stop failed %d " , ret ) ;
return ret ;
}
ret = sdw_bus_clk_stop ( & ctrl - > bus ) ;
if ( ret < 0 & & ret ! = - ENODATA ) {
dev_err ( dev , " bus clock stop failed %d " , ret ) ;
return ret ;
}
}
clk_disable_unprepare ( ctrl - > hclk ) ;
usleep_range ( 300 , 305 ) ;
2022-02-28 20:25:28 +03:00
if ( ctrl - > wake_irq > 0 ) {
if ( irqd_irq_disabled ( irq_get_irq_data ( ctrl - > wake_irq ) ) )
enable_irq ( ctrl - > wake_irq ) ;
}
2022-02-28 20:25:26 +03:00
return 0 ;
}
static const struct dev_pm_ops swrm_dev_pm_ops = {
SET_RUNTIME_PM_OPS ( swrm_runtime_suspend , swrm_runtime_resume , NULL )
} ;
2020-01-13 16:21:53 +03:00
static const struct of_device_id qcom_swrm_of_match [ ] = {
2020-09-17 15:01:38 +03:00
{ . compatible = " qcom,soundwire-v1.3.0 " , . data = & swrm_v1_3_data } ,
{ . compatible = " qcom,soundwire-v1.5.1 " , . data = & swrm_v1_5_data } ,
2022-07-01 10:17:07 +03:00
{ . compatible = " qcom,soundwire-v1.6.0 " , . data = & swrm_v1_6_data } ,
2022-10-26 14:02:10 +03:00
{ . compatible = " qcom,soundwire-v1.7.0 " , . data = & swrm_v1_5_data } ,
2023-04-18 12:54:46 +03:00
{ . compatible = " qcom,soundwire-v2.0.0 " , . data = & swrm_v2_0_data } ,
2020-01-13 16:21:53 +03:00
{ /* sentinel */ } ,
} ;
MODULE_DEVICE_TABLE ( of , qcom_swrm_of_match ) ;
static struct platform_driver qcom_swrm_driver = {
. probe = & qcom_swrm_probe ,
. remove = & qcom_swrm_remove ,
. driver = {
. name = " qcom-soundwire " ,
. of_match_table = qcom_swrm_of_match ,
2022-02-28 20:25:26 +03:00
. pm = & swrm_dev_pm_ops ,
2020-01-13 16:21:53 +03:00
}
} ;
module_platform_driver ( qcom_swrm_driver ) ;
MODULE_DESCRIPTION ( " Qualcomm soundwire driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;