Merge "ASoC: sm8250: Add soundwire port configuration"

This commit is contained in:
Linux Build Service Account 2018-12-18 10:31:10 -08:00 • committed by Gerrit - the friendly Code Review server
commit 8bff0e6c89
11 changed files with 313 additions and 83 deletions

View file

@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <soc/snd_event.h>
#include <linux/pm_runtime.h>
#include <soc/swr-common.h>
#include "bolero-cdc.h"
#include "internal.h"
@ -37,6 +38,41 @@ static u16 bolero_mclk_mux_tbl[MAX_MACRO][MCLK_MUX_MAX] = {
{TX_MACRO, VA_MACRO},
};
static bool bolero_is_valid_codec_dev(struct device *dev);
int bolero_set_port_map(struct snd_soc_component *component,
u32 size, void *data)
{
struct bolero_priv *priv = NULL;
struct swr_mstr_port_map *map = NULL;
u16 idx;
if (!component || (size == 0) || !data)
return -EINVAL;
priv = snd_soc_component_get_drvdata(component);
if (!priv)
return -EINVAL;
if (!bolero_is_valid_codec_dev(priv->dev)) {
dev_err(priv->dev, "%s: invalid codec\n", __func__);
return -EINVAL;
}
map = (struct swr_mstr_port_map *)data;
for (idx = 0; idx < size; idx++) {
if (priv->macro_params[map->id].set_port_map)
priv->macro_params[map->id].set_port_map(component,
map->uc,
SWR_MSTR_PORT_LEN,
map->swr_port_params);
map += 1;
}
return 0;
}
EXPORT_SYMBOL(bolero_set_port_map);
static void bolero_ahb_write_device(char __iomem *io_base,
u16 reg, u8 value)
{
@ -350,6 +386,7 @@ int bolero_register_macro(struct device *dev, u16 macro_id,
priv->macro_params[macro_id].dai_ptr = ops->dai_ptr;
priv->macro_params[macro_id].mclk_fn = ops->mclk_fn;
priv->macro_params[macro_id].event_handler = ops->event_handler;
priv->macro_params[macro_id].set_port_map = ops->set_port_map;
priv->macro_params[macro_id].dev = dev;
priv->current_mclk_mux_macro[macro_id] =
bolero_mclk_mux_tbl[macro_id][MCLK_MUX0];

View file

@ -51,6 +51,8 @@ struct macro_ops {
int (*event_handler)(struct snd_soc_component *component, u16 event,
u32 data);
int (*reg_wake_irq)(struct snd_soc_component *component, u32 data);
int (*set_port_map)(struct snd_soc_component *component, u32 uc,
u32 size, void *data);
char __iomem *io_base;
};
@ -69,6 +71,7 @@ int bolero_register_wake_irq(struct snd_soc_component *component, u32 data);
void bolero_clear_amic_tx_hold(struct device *dev, u16 adc_n);
int bolero_runtime_resume(struct device *dev);
int bolero_runtime_suspend(struct device *dev);
int bolero_set_port_map(struct snd_soc_component *component, u32 size, void *data);
#else
static inline int bolero_register_macro(struct device *dev,
u16 macro_id,
@ -107,13 +110,24 @@ static inline void bolero_clear_amic_tx_hold(struct device *dev, u16 adc_n)
static inline int bolero_register_wake_irq(struct snd_soc_component *component,
u32 data)
{
return 0;
}
static inline int bolero_runtime_resume(struct device *dev)
{
return 0;
}
static int bolero_runtime_suspend(struct device *dev)
{
return 0;
}
static inline int bolero_set_port_map(struct snd_soc_component *component,
u32 size, void *data)
{
return 0;
}
#endif /* CONFIG_SND_SOC_BOLERO */
#endif /* BOLERO_CDC_H */

View file

@ -12,6 +12,7 @@
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <soc/swr-common.h>
#include <soc/swr-wcd.h>
#include "bolero-cdc.h"
@ -701,6 +702,29 @@ static bool rx_macro_get_data(struct snd_soc_component *component,
return true;
}
static int rx_macro_set_port_map(struct snd_soc_component *component,
u32 usecase, u32 size, void *data)
{
struct device *rx_dev = NULL;
struct rx_macro_priv *rx_priv = NULL;
struct swrm_port_config port_cfg;
int ret = 0;
if (!rx_macro_get_data(component, &rx_dev, &rx_priv, __func__))
return -EINVAL;
memset(&port_cfg, 0, sizeof(port_cfg));
port_cfg.uc = usecase;
port_cfg.size = size;
port_cfg.params = data;
ret = swrm_wcd_notify(
rx_priv->swr_ctrl_data[0].rx_swr_pdev,
SWR_SET_PORT_MAP, &port_cfg);
return ret;
}
static int rx_macro_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@ -3366,6 +3390,7 @@ static void rx_macro_init_ops(struct macro_ops *ops, char __iomem *rx_io_base)
ops->num_dais = ARRAY_SIZE(rx_macro_dai);
ops->mclk_fn = rx_macro_mclk_ctrl;
ops->event_handler = rx_macro_event_handler;
ops->set_port_map = rx_macro_set_port_map;
}
static int rx_macro_probe(struct platform_device *pdev)

View file

@ -11,6 +11,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <soc/swr-common.h>
#include <soc/swr-wcd.h>
#include "bolero-cdc.h"
#include "bolero-cdc-registers.h"
@ -1709,6 +1710,29 @@ err:
return;
}
static int tx_macro_set_port_map(struct snd_soc_component *component,
u32 usecase, u32 size, void *data)
{
struct device *tx_dev = NULL;
struct tx_macro_priv *tx_priv = NULL;
struct swrm_port_config port_cfg;
int ret = 0;
if (!tx_macro_get_data(component, &tx_dev, &tx_priv, __func__))
return -EINVAL;
memset(&port_cfg, 0, sizeof(port_cfg));
port_cfg.uc = usecase;
port_cfg.size = size;
port_cfg.params = data;
ret = swrm_wcd_notify(
tx_priv->swr_ctrl_data[0].tx_swr_pdev,
SWR_SET_PORT_MAP, &port_cfg);
return ret;
}
static void tx_macro_init_ops(struct macro_ops *ops,
char __iomem *tx_io_base)
{
@ -1721,6 +1745,7 @@ static void tx_macro_init_ops(struct macro_ops *ops,
ops->mclk_fn = tx_macro_mclk_ctrl;
ops->event_handler = tx_macro_event_handler;
ops->reg_wake_irq = tx_macro_reg_wake_irq;
ops->set_port_map = tx_macro_set_port_map;
}
static int tx_macro_probe(struct platform_device *pdev)

View file

@ -10,6 +10,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <soc/swr-common.h>
#include <soc/swr-wcd.h>
#include "bolero-cdc.h"
@ -452,6 +453,29 @@ static bool wsa_macro_get_data(struct snd_soc_component *component,
return true;
}
static int wsa_macro_set_port_map(struct snd_soc_component *component,
u32 usecase, u32 size, void *data)
{
struct device *wsa_dev = NULL;
struct wsa_macro_priv *wsa_priv = NULL;
struct swrm_port_config port_cfg;
int ret = 0;
if (!wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__))
return -EINVAL;
memset(&port_cfg, 0, sizeof(port_cfg));
port_cfg.uc = usecase;
port_cfg.size = size;
port_cfg.params = data;
ret = swrm_wcd_notify(
wsa_priv->swr_ctrl_data[0].wsa_swr_pdev,
SWR_SET_PORT_MAP, &port_cfg);
return ret;
}
/**
* wsa_macro_set_spkr_gain_offset - offset the speaker path
* gain with the given offset value.
@ -2770,6 +2794,7 @@ static void wsa_macro_init_ops(struct macro_ops *ops,
ops->num_dais = ARRAY_SIZE(wsa_macro_dai);
ops->mclk_fn = wsa_macro_mclk_ctrl;
ops->event_handler = wsa_macro_event_handler;
ops->set_port_map = wsa_macro_set_port_map;
}
static int wsa_macro_probe(struct platform_device *pdev)

58
asoc/sm8250-port-config.h Normal file
View file

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#ifndef _SM8250_PORT_CONFIG
#define _SM8250_PORT_CONFIG
#include <soc/swr-common.h>
#define WSA_MSTR_PORT_MASK 0xFF
/*
* Add port configuration in the format
*{ si, off1, off2, hstart, hstop, wd_len, bp_mode, bgp_ctrl, lane_ctrl}
*/
static struct port_params wsa_frame_params_default[SWR_MSTR_PORT_LEN] = {
{7, 1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{31, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{63, 12, 31, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{7, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{31, 18, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{63, 13, 31, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{15, 7, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{15, 10, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
};
static struct port_params rx_frame_params_default[SWR_MSTR_PORT_LEN] = {
{3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1},
{31, 0, 0, 3, 6, 7, 0, 0xFF, 0},
{31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0},
{3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0},
{0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0},
};
static struct port_params rx_frame_params_dsd[SWR_MSTR_PORT_LEN] = {
{3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1},
{31, 0, 0, 3, 6, 7, 0, 0xFF, 0},
{31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0},
{7, 9, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0},
{3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 3, 0},
};
/* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */
static struct port_params tx_frame_params_default[SWR_MSTR_PORT_LEN] = {
{1, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX1 */
{1, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1}, /* TX2 */
{3, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0}, /* TX3 */
};
static struct swr_mstr_port_map sm_port_map[] = {
{TX_MACRO, SWR_UC0, tx_frame_params_default},
{RX_MACRO, SWR_UC0, rx_frame_params_default},
{RX_MACRO, SWR_UC1, rx_frame_params_dsd},
{WSA_MACRO, SWR_UC0, wsa_frame_params_default},
};
#endif /* _SM8250_PORT_CONFIG */

45
include/soc/swr-common.h Normal file
View file

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015, 2017-2018 The Linux Foundation. All rights reserved.
*/
#ifndef _LINUX_SWR_COMMON_H
#define _LINUX_SWR_COMMON_H
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/bitops.h>
enum {
SWR_UC0 = 0,
SWR_UC1,
SWR_UC_MAX,
};
struct port_params {
u8 si;
u8 off1;
u8 off2;
u8 hstart;/* head start */
u8 hstop; /* head stop */
u8 wd_len;/* word length */
u8 bp_mode; /* block pack mode */
u8 bgp_ctrl;/* block group control */
u8 lane_ctrl;/* lane to be used */
};
struct swrm_port_config {
u32 size;
u32 uc;
void *params;
};
struct swr_mstr_port_map {
u32 id;
u32 uc;
struct port_params *swr_port_params;
};
#define SWR_MSTR_PORT_LEN 8 /* Number of master ports */
#endif /* _LINUX_SWR_COMMON_H */

View file

@ -20,6 +20,7 @@ enum {
SWR_DEVICE_SSR_DOWN,
SWR_DEVICE_SSR_UP,
SWR_REGISTER_WAKE_IRQ,
SWR_SET_PORT_MAP,
};
struct swr_mstr_port {

View file

@ -19,15 +19,17 @@
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <soc/soundwire.h>
#include <soc/swr-wcd.h>
#include <soc/swr-common.h>
#include <linux/regmap.h>
#include <dsp/msm-audio-event-notify.h>
#include "swrm_registers.h"
#include "swr-mstr-ctrl.h"
#include "swrm_port_config.h"
#define SWRM_SYSTEM_RESUME_TIMEOUT_MS 700
#define SWRM_SYS_SUSPEND_WAIT 1
#define SWRM_DSD_PARAMS_PORT 4
#define SWR_BROADCAST_CMD_ID 0x0F
#define SWR_AUTO_SUSPEND_DELAY 3 /* delay in sec */
#define SWR_DEV_ID_MASK 0xFFFFFFFFFFFF
@ -377,27 +379,16 @@ static void copy_port_tables(struct swr_mstr_ctrl *swrm,
static int swrm_get_port_config(struct swr_mstr_ctrl *swrm)
{
struct port_params *params;
u32 usecase = 0;
switch (swrm->master_id) {
case MASTER_ID_WSA:
params = wsa_frame_superset;
break;
case MASTER_ID_RX:
/* Two RX tables for dsd and without dsd enabled */
if (swrm->mport_cfg[4].port_en)
params = rx_frame_params_dsd;
else
params = rx_frame_params;
break;
case MASTER_ID_TX:
params = tx_frame_params_superset;
break;
default: /* MASTER_GENERIC*/
/* computer generic frame parameters */
return -EINVAL;
}
/* TODO - Send usecase information to avoid checking for master_id */
if (swrm->mport_cfg[SWRM_DSD_PARAMS_PORT].port_en &&
(swrm->master_id == MASTER_ID_RX))
usecase = 1;
params = swrm->port_param[usecase];
copy_port_tables(swrm, params);
return 0;
}
@ -2187,6 +2178,53 @@ int swrm_register_wake_irq(struct swr_mstr_ctrl *swrm)
return ret;
}
static int swrm_alloc_port_mem(struct device *dev, struct swr_mstr_ctrl *swrm,
u32 uc, u32 size)
{
if (!swrm->port_param) {
swrm->port_param = devm_kzalloc(dev,
sizeof(swrm->port_param) * SWR_UC_MAX,
GFP_KERNEL);
if (!swrm->port_param)
return -ENOMEM;
}
if (!swrm->port_param[uc]) {
swrm->port_param[uc] = devm_kcalloc(dev, size,
sizeof(struct port_params),
GFP_KERNEL);
if (!swrm->port_param[uc])
return -ENOMEM;
} else {
dev_err_ratelimited(swrm->dev, "%s: called more than once\n",
__func__);
}
return 0;
}
static int swrm_copy_port_config(struct swr_mstr_ctrl *swrm,
struct swrm_port_config *port_cfg,
u32 size)
{
int idx;
struct port_params *params;
int uc = port_cfg->uc;
int ret = 0;
for (idx = 0; idx < size; idx++) {
params = &((struct port_params *)port_cfg->params)[idx];
if (!params) {
dev_err(swrm->dev, "%s: Invalid params\n", __func__);
ret = -EINVAL;
break;
}
memcpy(&swrm->port_param[uc][idx], params,
sizeof(struct port_params));
}
return ret;
}
/**
* swrm_wcd_notify - parent device can notify to soundwire master through
* this function
@ -2200,6 +2238,7 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
int ret = 0;
struct swr_master *mstr;
struct swr_device *swr_dev;
struct swrm_port_config *port_cfg;
if (!pdev) {
pr_err("%s: pdev is NULL\n", __func__);
@ -2327,6 +2366,27 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
mutex_unlock(&swrm->mlock);
}
break;
case SWR_SET_PORT_MAP:
if (!data) {
dev_err(swrm->dev, "%s: data is NULL for id=%d\n",
__func__, id);
ret = -EINVAL;
} else {
mutex_lock(&swrm->mlock);
port_cfg = (struct swrm_port_config *)data;
if (!port_cfg->size) {
ret = -EINVAL;
goto done;
}
ret = swrm_alloc_port_mem(&pdev->dev, swrm,
port_cfg->uc, port_cfg->size);
if (!ret)
swrm_copy_port_config(swrm, port_cfg,
port_cfg->size);
done:
mutex_unlock(&swrm->mlock);
}
break;
default:
dev_err(swrm->dev, "%s: swr master unknown id %d\n",
__func__, id);

View file

@ -9,6 +9,7 @@
#include <soc/swr-wcd.h>
#include <linux/pm_qos.h>
#include <soc/qcom/pm.h>
#include <soc/swr-common.h>
#define SWR_ROW_48 0
#define SWR_ROW_50 1
@ -61,18 +62,6 @@ struct usecase {
u32 chrate;
};
struct port_params {
u8 si;
u8 off1;
u8 off2;
u8 hstart;/* head start */
u8 hstop; /* head stop */
u8 wd_len;/* word length */
u8 bp_mode; /* block pack mode */
u8 bgp_ctrl;/* block group control */
u8 lane_ctrl;/* lane to be used */
};
struct swrm_mports {
struct list_head port_req_list;
bool port_en;
@ -163,6 +152,8 @@ struct swr_mstr_ctrl {
wait_queue_head_t pm_wq;
int wlock_holders;
u32 intr_mask;
struct port_params **port_param;
u8 num_usecase;
};
#endif /* _SWR_WCD_CTRL_H */

View file

@ -1,51 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
*/
#ifndef _SWRM_PORT_CONFIG
#define _SWRM_PORT_CONFIG
#define WSA_MSTR_PORT_MASK 0xFF
/*
* Add port configuration in the format
*{ si, off1, off2, hstart, hstop, wd_len, bp_mode, bgp_ctrl, lane_ctrl}
*/
struct port_params wsa_frame_superset[SWR_MSTR_PORT_LEN] = {
{7, 1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{31, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{63, 12, 31, 0xFF, 0xFF, 0xFF, 0x1, 0xFF, 0xFF},
{7, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{31, 18, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{63, 13, 31, 0xFF, 0xFF, 0xFF, 0x1, 0xFF, 0xFF},
{15, 7, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{15, 10, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
};
struct port_params rx_frame_params[SWR_MSTR_PORT_LEN] = {
{3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1},
{31, 0, 0, 3, 6, 7, 0, 0xFF, 0},
{31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0},
{3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0},
{0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0},
};
struct port_params rx_frame_params_dsd[SWR_MSTR_PORT_LEN] = {
{3, 0, 0, 0xFF, 0xFF, 1, 0xFF, 0xFF, 1},
{31, 0, 0, 3, 6, 7, 0, 0xFF, 0},
{31, 11, 11, 0xFF, 0xFF, 4, 1, 0xFF, 0},
{7, 9, 0, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0},
{3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 3, 0},
};
struct port_params tx_frame_params_superset[SWR_MSTR_PORT_LEN] = {
{1, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},
{1, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1},
{3, 1, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0},
{3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1},
};
#endif /* _SWRM_REGISTERS_H */