Loading asoc/msm-lsm-client.c +114 −60 Original line number Diff line number Diff line Loading @@ -53,8 +53,8 @@ static struct snd_pcm_hardware msm_pcm_hardware_capture = { SNDRV_PCM_RATE_48000), .rate_min = 16000, .rate_max = 48000, .channels_min = 1, .channels_max = 4, .channels_min = LSM_INPUT_NUM_CHANNELS_MIN, .channels_max = LSM_INPUT_NUM_CHANNELS_MAX, .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, Loading Loading @@ -116,11 +116,11 @@ static int msm_lsm_queue_lab_buffer(struct lsm_priv *prtd, int i) rtd = prtd->substream->private_data; if (!prtd->lsm_client->lab_buffer || i >= prtd->lsm_client->hw_params.period_count) { i >= prtd->lsm_client->out_hw_params.period_count) { dev_err(rtd->dev, "%s: Lab buffer not setup %pK incorrect index %d period count %d\n", __func__, prtd->lsm_client->lab_buffer, i, prtd->lsm_client->hw_params.period_count); prtd->lsm_client->out_hw_params.period_count); return -EINVAL; } cmd_read.buf_addr_lsw = Loading Loading @@ -165,7 +165,7 @@ static int lsm_lab_buffer_sanity(struct lsm_priv *prtd, prtd->lsm_client->lab_buffer); return -EINVAL; } for (i = 0; i < prtd->lsm_client->hw_params.period_count; i++) { for (i = 0; i < prtd->lsm_client->out_hw_params.period_count; i++) { if ((lower_32_bits(prtd->lsm_client->lab_buffer[i].phys) == read_done->buf_addr_lsw) && (msm_audio_populate_upper_32_bits Loading Loading @@ -240,11 +240,11 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, "%s: process read done index %d\n", __func__, buf_index); if (buf_index >= prtd->lsm_client->hw_params.period_count) { prtd->lsm_client->out_hw_params.period_count) { dev_err(rtd->dev, "%s: Invalid index %d buf_index max cnt %d\n", __func__, buf_index, prtd->lsm_client->hw_params.period_count); prtd->lsm_client->out_hw_params.period_count); return; } prtd->dma_write += read_done->total_size; Loading @@ -253,7 +253,7 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, wake_up(&prtd->period_wait); /* queue the next period buffer */ buf_index = (buf_index + 1) % prtd->lsm_client->hw_params.period_count; prtd->lsm_client->out_hw_params.period_count; rc = msm_lsm_queue_lab_buffer(prtd, buf_index); if (rc) dev_err(rtd->dev, Loading Loading @@ -405,8 +405,8 @@ static int msm_lsm_lab_buffer_alloc(struct lsm_priv *lsm, int alloc) dma_buf->private_data = NULL; dma_buf->area = lsm->lsm_client->lab_buffer[0].data; dma_buf->addr = lsm->lsm_client->lab_buffer[0].phys; dma_buf->bytes = lsm->lsm_client->hw_params.buf_sz * lsm->lsm_client->hw_params.period_count; dma_buf->bytes = lsm->lsm_client->out_hw_params.buf_sz * lsm->lsm_client->out_hw_params.period_count; snd_pcm_set_runtime_buffer(lsm->substream, dma_buf); } else { ret = q6lsm_lab_buffer_alloc(lsm->lsm_client, alloc); Loading Loading @@ -1260,7 +1260,10 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, break; } case SNDRV_LSM_LAB_CONTROL: { u32 enable; struct lsm_hw_params *out_hw_params = &prtd->lsm_client->out_hw_params; u8 chmap[out_hw_params->num_chs]; u32 enable, ch_idx; if (copy_from_user(&enable, arg, sizeof(enable))) { dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n", Loading @@ -1270,7 +1273,14 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, dev_dbg(rtd->dev, "%s: ioctl %s, enable = %d\n", __func__, "SNDRV_LSM_LAB_CONTROL", enable); if (!prtd->lsm_client->started) { if (prtd->lsm_client->started) { dev_err(rtd->dev, "%s: ioctl %s issued after start", __func__, "SNDRV_LSM_LAB_CONTROL"); rc = -EINVAL; break; } if (prtd->lsm_client->lab_enable == enable) { dev_dbg(rtd->dev, "%s: Lab for session %d already %s\n", Loading @@ -1279,6 +1289,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, rc = 0; break; } rc = q6lsm_lab_control(prtd->lsm_client, enable); if (rc) { dev_err(rtd->dev, Loading @@ -1286,23 +1297,37 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, __func__, "SNDRV_LAB_CONTROL", rc, enable ? "enable" : "disable", prtd->lsm_client->session); } else { break; } rc = msm_lsm_lab_buffer_alloc(prtd, enable ? LAB_BUFFER_ALLOC : LAB_BUFFER_DEALLOC); if (rc) if (rc) { dev_err(rtd->dev, "%s: msm_lsm_lab_buffer_alloc failed rc %d for %s", __func__, rc, enable ? "ALLOC" : "DEALLOC"); if (!rc) prtd->lsm_client->lab_enable = enable; } } else { dev_err(rtd->dev, "%s: ioctl %s issued after start", __func__, "SNDRV_LSM_LAB_CONTROL"); rc = -EINVAL; break; } prtd->lsm_client->lab_enable = enable; memset(chmap, 0, out_hw_params->num_chs); /* * First channel to be read from lab is always the * best channel (0xff). For second channel onwards, * the channel indices are 0, 1, .. etc */ chmap[0] = 0xFF; for (ch_idx = 1; ch_idx < out_hw_params->num_chs; ch_idx++) chmap[ch_idx] = ch_idx - 1; rc = q6lsm_lab_out_ch_cfg(prtd->lsm_client, chmap); if (rc) dev_err(rtd->dev, "%s: Failed to set lab out ch cfg %d\n", __func__, rc); break; } case SNDRV_LSM_STOP_LAB: Loading Loading @@ -1354,6 +1379,23 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, } break; } case SNDRV_LSM_SET_INPUT_HW_PARAMS: { struct lsm_hw_params *in_params; struct snd_lsm_input_hw_params params; if (copy_from_user(¶ms, arg, sizeof(params))) { dev_err(rtd->dev, "%s: %s: copy_from_user failed\n", __func__, "LSM_SET_INPUT_HW_PARAMS"); return -EFAULT; } in_params = &prtd->lsm_client->in_hw_params; in_params->sample_rate = params.sample_rate; in_params->sample_size = params.bit_width; in_params->num_chs = params.num_channels; break; } default: dev_dbg(rtd->dev, Loading Loading @@ -2241,7 +2283,7 @@ static int msm_lsm_prepare(struct snd_pcm_substream *substream) return -EINVAL; } if (q6lsm_set_media_fmt_params(prtd->lsm_client)) if (q6lsm_set_media_fmt_v2_params(prtd->lsm_client)) dev_dbg(rtd->dev, "%s: failed to set lsm media fmt params\n", __func__); Loading Loading @@ -2339,7 +2381,8 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; struct lsm_priv *prtd = runtime->private_data; struct lsm_hw_params *hw_params = NULL; struct lsm_hw_params *out_hw_params = NULL; struct lsm_hw_params *in_hw_params = NULL; struct snd_soc_pcm_runtime *rtd; if (!substream->private_data) { Loading @@ -2354,37 +2397,48 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, __func__, prtd, params); return -EINVAL; } hw_params = &prtd->lsm_client->hw_params; hw_params->num_chs = params_channels(params); hw_params->period_count = params_periods(params); hw_params->sample_rate = params_rate(params); if (((hw_params->sample_rate != 16000) && (hw_params->sample_rate != 48000)) || (hw_params->period_count == 0)) { in_hw_params = &prtd->lsm_client->in_hw_params; out_hw_params = &prtd->lsm_client->out_hw_params; out_hw_params->num_chs = params_channels(params); out_hw_params->period_count = params_periods(params); out_hw_params->sample_rate = params_rate(params); if (((out_hw_params->sample_rate != 16000) && (out_hw_params->sample_rate != 48000)) || (out_hw_params->period_count == 0)) { dev_err(rtd->dev, "%s: Invalid Params sample rate %d period count %d\n", __func__, hw_params->sample_rate, hw_params->period_count); __func__, out_hw_params->sample_rate, out_hw_params->period_count); return -EINVAL; } if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE) { hw_params->sample_size = 16; out_hw_params->sample_size = 16; } else if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE) { hw_params->sample_size = 24; out_hw_params->sample_size = 24; } else { dev_err(rtd->dev, "%s: Invalid Format 0x%x\n", __func__, params_format(params)); return -EINVAL; } hw_params->buf_sz = params_buffer_bytes(params) / hw_params->period_count; out_hw_params->buf_sz = params_buffer_bytes(params) / out_hw_params->period_count; dev_dbg(rtd->dev, "%s: channels %d sample rate %d sample size %d buffer size %d period count %d\n", __func__, hw_params->num_chs, hw_params->sample_rate, hw_params->sample_size, hw_params->buf_sz, hw_params->period_count); __func__, out_hw_params->num_chs, out_hw_params->sample_rate, out_hw_params->sample_size, out_hw_params->buf_sz, out_hw_params->period_count); /* * copy the out_hw_params to in_hw_params. in_hw_params will be * over-written with LSM_SET_INPUT_HW_PARAMS ioctl from userspace. * If this ioctl is not set, then it is assumed that input and * output hw params for LSM are the same. * Currently the period_count and buf_sz are unused for input params. */ memcpy(in_hw_params, out_hw_params, sizeof(struct lsm_hw_params)); return 0; } Loading Loading @@ -2456,7 +2510,7 @@ static int msm_lsm_pcm_copy(struct snd_pcm_substream *substream, int ch, return -EIO; } prtd->appl_cnt = prtd->appl_cnt % prtd->lsm_client->hw_params.period_count; prtd->lsm_client->out_hw_params.period_count; pcm_buf = prtd->lsm_client->lab_buffer[prtd->appl_cnt].data; dev_dbg(rtd->dev, "%s: copy the pcm data size %lu\n", Loading @@ -2474,7 +2528,7 @@ static int msm_lsm_pcm_copy(struct snd_pcm_substream *substream, int ch, return -EINVAL; } prtd->appl_cnt = (prtd->appl_cnt + 1) % prtd->lsm_client->hw_params.period_count; prtd->lsm_client->out_hw_params.period_count; atomic_dec(&prtd->buf_count); return 0; } Loading dsp/q6lsm.c +157 −44 Original line number Diff line number Diff line Loading @@ -1028,38 +1028,33 @@ int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, } EXPORT_SYMBOL(q6lsm_set_fwk_mode_cfg); static int q6lsm_arrange_mch_map(struct lsm_param_media_fmt *media_fmt, int channel_count) static int q6lsm_arrange_mch_map(uint8_t *ch_map, int ch_cnt) { int rc = 0; int ch_idx; u8 mch_map[LSM_V3P0_MAX_NUM_CHANNELS] = { PCM_CHANNEL_FL, PCM_CHANNEL_FR, PCM_CHANNEL_FC, PCM_CHANNEL_LS, PCM_CHANNEL_RS, PCM_CHANNEL_LFE, PCM_CHANNEL_LB, PCM_CHANNEL_RB, PCM_CHANNEL_CS}; memset(media_fmt->channel_mapping, 0, LSM_MAX_NUM_CHANNELS); switch (channel_count) { case 1: media_fmt->channel_mapping[0] = PCM_CHANNEL_FC; break; case 2: media_fmt->channel_mapping[0] = PCM_CHANNEL_FL; media_fmt->channel_mapping[1] = PCM_CHANNEL_FR; break; case 3: media_fmt->channel_mapping[0] = PCM_CHANNEL_FL; media_fmt->channel_mapping[1] = PCM_CHANNEL_FR; media_fmt->channel_mapping[2] = PCM_CHANNEL_FC; break; case 4: media_fmt->channel_mapping[0] = PCM_CHANNEL_FL; media_fmt->channel_mapping[1] = PCM_CHANNEL_FR; media_fmt->channel_mapping[2] = PCM_CHANNEL_LS; media_fmt->channel_mapping[3] = PCM_CHANNEL_RS; break; default: pr_err("%s: invalid num_chan %d\n", __func__, channel_count); rc = -EINVAL; break; if (ch_cnt > LSM_V3P0_MAX_NUM_CHANNELS) { pr_err("%s: invalid num_chan %d\n", __func__, ch_cnt); return -EINVAL; } return rc; if (ch_cnt == 1) { ch_map[0] = PCM_CHANNEL_FC; } else if (ch_cnt == 4) { ch_map[0] = PCM_CHANNEL_FL; ch_map[1] = PCM_CHANNEL_FR; ch_map[2] = PCM_CHANNEL_LS; ch_map[3] = PCM_CHANNEL_RS; } else { for (ch_idx = 0; ch_idx < ch_cnt; ch_idx++) ch_map[ch_idx] = mch_map[ch_idx]; } return 0; } /** Loading @@ -1073,7 +1068,7 @@ static int q6lsm_arrange_mch_map(struct lsm_param_media_fmt *media_fmt, int q6lsm_set_media_fmt_params(struct lsm_client *client) { struct lsm_param_media_fmt media_fmt; struct lsm_hw_params param = client->hw_params; struct lsm_hw_params in_param = client->in_hw_params; struct param_hdr_v3 media_fmt_hdr; int rc = 0; Loading @@ -1091,10 +1086,11 @@ int q6lsm_set_media_fmt_params(struct lsm_client *client) media_fmt_hdr.param_size = sizeof(media_fmt); media_fmt.minor_version = QLSM_PARAM_ID_MINOR_VERSION_2; media_fmt.sample_rate = param.sample_rate; media_fmt.num_channels = param.num_chs; media_fmt.bit_width = param.sample_size; rc = q6lsm_arrange_mch_map(&media_fmt, media_fmt.num_channels); media_fmt.sample_rate = in_param.sample_rate; media_fmt.num_channels = in_param.num_chs; media_fmt.bit_width = in_param.sample_size; rc = q6lsm_arrange_mch_map(media_fmt.channel_mapping, media_fmt.num_channels); if (rc) goto err_ret; Loading @@ -1112,6 +1108,65 @@ int q6lsm_set_media_fmt_params(struct lsm_client *client) } EXPORT_SYMBOL(q6lsm_set_media_fmt_params); /* * q6lsm_set_media_fmt_v2_params - * command to set LSM media fmt (version2) params * * @client: LSM client handle * * Returns 0 on success or error on failure */ int q6lsm_set_media_fmt_v2_params(struct lsm_client *client) { u8 *param_buf; struct lsm_param_media_fmt_v2 *media_fmt_v2; struct lsm_hw_params *in_param = &client->in_hw_params; struct param_hdr_v3 media_fmt_v2_hdr; int param_len = 0, rc = 0; memset(&media_fmt_v2_hdr, 0, sizeof(media_fmt_v2_hdr)); param_len = sizeof(*media_fmt_v2) + (sizeof(uint8_t) * in_param->num_chs); /* Add padding to make sure total length is 4-byte aligned */ if (param_len % 4) param_len += (4 - (param_len % 4)); param_buf = kzalloc(param_len, GFP_KERNEL); if (!param_buf) return -ENOMEM; media_fmt_v2 = (struct lsm_param_media_fmt_v2 *) param_buf; media_fmt_v2->minor_version = QLSM_PARAM_ID_MINOR_VERSION; media_fmt_v2->sample_rate = in_param->sample_rate; media_fmt_v2->num_channels = in_param->num_chs; media_fmt_v2->bit_width = in_param->sample_size; rc = q6lsm_arrange_mch_map(media_fmt_v2->channel_mapping, in_param->num_chs); if (rc) goto err_mch_map; media_fmt_v2_hdr.module_id = LSM_MODULE_ID_FRAMEWORK; media_fmt_v2_hdr.instance_id = INSTANCE_ID_0; media_fmt_v2_hdr.param_id = LSM_PARAM_ID_MEDIA_FMT_V2; media_fmt_v2_hdr.param_size = param_len; pr_debug("%s: sample rate= %d, channels %d bit width %d\n", __func__, media_fmt_v2->sample_rate, media_fmt_v2->num_channels, media_fmt_v2->bit_width); rc = q6lsm_pack_and_set_params(client, &media_fmt_v2_hdr, param_buf, LSM_SESSION_CMD_SET_PARAMS_V2); if (rc) pr_err("%s: Failed set_params, rc %d\n", __func__, rc); err_mch_map: kfree(param_buf); return rc; } EXPORT_SYMBOL(q6lsm_set_media_fmt_v2_params); /** * q6lsm_set_data - * Command to set LSM data Loading Loading @@ -2051,6 +2106,62 @@ int q6lsm_lab_control(struct lsm_client *client, u32 enable) } EXPORT_SYMBOL(q6lsm_lab_control); /* * q6lsm_lab_out_ch_cfg - * Command to set the channel configuration * for look-ahead buffer. * * @client: LSM client handle * @ch_map: Channel map indicating the order * of channels to be configured. * * Returns 0 on success or error on failure */ int q6lsm_lab_out_ch_cfg(struct lsm_client *client, u8 *ch_map) { u8 *param_buf; struct lsm_param_lab_out_ch_cfg *lab_out_cfg; struct param_hdr_v3 lab_out_cfg_hdr; struct lsm_hw_params *out_params = &client->out_hw_params; int i, rc = 0, param_len = 0; param_len = sizeof(*lab_out_cfg) + sizeof(u8) * out_params->num_chs; if (param_len % 4) param_len += (4 - (param_len % 4)); param_buf = kzalloc(param_len, GFP_KERNEL); if (!param_buf) return -ENOMEM; lab_out_cfg = (struct lsm_param_lab_out_ch_cfg *) param_buf; lab_out_cfg->minor_version = QLSM_PARAM_ID_MINOR_VERSION; lab_out_cfg->num_channels = out_params->num_chs; for (i = 0; i < out_params->num_chs; i++) lab_out_cfg->channel_indices[i] = ch_map[i]; memset(&lab_out_cfg_hdr, 0, sizeof(lab_out_cfg_hdr)); lab_out_cfg_hdr.module_id = LSM_MODULE_ID_LAB; lab_out_cfg_hdr.instance_id = INSTANCE_ID_0; lab_out_cfg_hdr.param_id = LSM_PARAM_ID_LAB_OUTPUT_CHANNEL_CONFIG; lab_out_cfg_hdr.param_size = param_len; rc = q6lsm_pack_and_set_params(client, &lab_out_cfg_hdr, param_buf, LSM_SESSION_CMD_SET_PARAMS_V2); if (rc) pr_err("%s: Lab out channel config failed %d\n", __func__, rc); kfree(param_buf); return rc; } EXPORT_SYMBOL(q6lsm_lab_out_ch_cfg); /** * q6lsm_stop_lab - * command to stop LSM LAB Loading Loading @@ -2117,6 +2228,7 @@ int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc) { int ret = 0, i = 0; size_t allocate_size = 0, len = 0; struct lsm_hw_params *out_params = &client->out_hw_params; if (!client) { pr_err("%s: invalid client\n", __func__); Loading @@ -2126,20 +2238,20 @@ int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc) if (client->lab_buffer) { pr_err("%s: buffers are allocated period count %d period size %d\n", __func__, client->hw_params.period_count, client->hw_params.buf_sz); out_params->period_count, out_params->buf_sz); return -EINVAL; } allocate_size = client->hw_params.period_count * client->hw_params.buf_sz; allocate_size = out_params->period_count * out_params->buf_sz; allocate_size = PAGE_ALIGN(allocate_size); client->lab_buffer = kzalloc(sizeof(struct lsm_lab_buffer) * client->hw_params.period_count, GFP_KERNEL); out_params->period_count, GFP_KERNEL); if (!client->lab_buffer) { pr_err("%s: memory allocation for lab buffer failed count %d\n" , __func__, client->hw_params.period_count); out_params->period_count); return -ENOMEM; } ret = msm_audio_ion_alloc(&client->lab_buffer[0].dma_buf, Loading Loading @@ -2170,16 +2282,17 @@ int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc) __func__, client->lab_buffer[0].mem_map_handle, &client->lab_buffer[0].phys, client->hw_params.buf_sz); for (i = 0; i < client->hw_params.period_count; i++) { out_params->buf_sz); for (i = 0; i < out_params->period_count; i++) { client->lab_buffer[i].phys = client->lab_buffer[0].phys + (i * client->hw_params.buf_sz); (i * out_params->buf_sz); client->lab_buffer[i].size = client->hw_params.buf_sz; out_params->buf_sz; client->lab_buffer[i].data = (u8 *)(client->lab_buffer[0].data) + (i * client->hw_params.buf_sz); (i * out_params->buf_sz); client->lab_buffer[i].mem_map_handle = client->lab_buffer[0].mem_map_handle; } Loading include/dsp/apr_audio-v2.h +2 −0 Original line number Diff line number Diff line Loading @@ -9951,6 +9951,8 @@ struct avcs_fwk_ver_info { #define LSM_PARAM_ID_POLLING_ENABLE (0x00012C1B) #define LSM_PARAM_ID_MEDIA_FMT (0x00012C1E) #define LSM_PARAM_ID_FWK_MODE_CONFIG (0x00012C27) #define LSM_PARAM_ID_MEDIA_FMT_V2 (0x00012C32) #define LSM_PARAM_ID_LAB_OUTPUT_CHANNEL_CONFIG (0x00012C2D) /* HW MAD specific */ #define AFE_MODULE_HW_MAD (0x00010230) Loading include/dsp/q6lsm.h +20 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #define ADM_LSM_PORT_ID 0xADCB #define LSM_MAX_NUM_CHANNELS 8 #define LSM_V3P0_MAX_NUM_CHANNELS 9 typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv); Loading Loading @@ -82,7 +83,8 @@ struct lsm_client { bool lab_enable; bool lab_started; struct lsm_lab_buffer *lab_buffer; struct lsm_hw_params hw_params; struct lsm_hw_params out_hw_params; struct lsm_hw_params in_hw_params; bool use_topology; int session_state; bool poll_enable; Loading Loading @@ -157,6 +159,15 @@ struct lsm_param_media_fmt { uint8_t channel_mapping[LSM_MAX_NUM_CHANNELS]; } __packed; struct lsm_param_media_fmt_v2 { uint32_t minor_version; uint32_t sample_rate; uint16_t bit_width; uint16_t num_channels; uint8_t channel_mapping[0]; } __packed; struct lsm_param_confidence_levels { uint8_t num_confidence_levels; uint8_t confidence_levels[0]; Loading Loading @@ -192,6 +203,12 @@ struct lsm_param_lab_config { uint32_t wake_up_latency_ms; } __packed; struct lsm_param_lab_out_ch_cfg { uint32_t minor_version; uint32_t num_channels; uint8_t channel_indices[0]; } __packed; struct lsm_cmd_read { struct apr_hdr hdr; uint32_t buf_addr_lsw; Loading Loading @@ -250,4 +267,6 @@ void q6lsm_sm_set_param_data(struct lsm_client *client, int q6lsm_set_port_connected(struct lsm_client *client); int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, uint32_t event_mode); int q6lsm_set_media_fmt_params(struct lsm_client *client); int q6lsm_set_media_fmt_v2_params(struct lsm_client *client); int q6lsm_lab_out_ch_cfg(struct lsm_client *client, u8 *ch_map); #endif /* __Q6LSM_H__ */ Loading
asoc/msm-lsm-client.c +114 −60 Original line number Diff line number Diff line Loading @@ -53,8 +53,8 @@ static struct snd_pcm_hardware msm_pcm_hardware_capture = { SNDRV_PCM_RATE_48000), .rate_min = 16000, .rate_max = 48000, .channels_min = 1, .channels_max = 4, .channels_min = LSM_INPUT_NUM_CHANNELS_MIN, .channels_max = LSM_INPUT_NUM_CHANNELS_MAX, .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, Loading Loading @@ -116,11 +116,11 @@ static int msm_lsm_queue_lab_buffer(struct lsm_priv *prtd, int i) rtd = prtd->substream->private_data; if (!prtd->lsm_client->lab_buffer || i >= prtd->lsm_client->hw_params.period_count) { i >= prtd->lsm_client->out_hw_params.period_count) { dev_err(rtd->dev, "%s: Lab buffer not setup %pK incorrect index %d period count %d\n", __func__, prtd->lsm_client->lab_buffer, i, prtd->lsm_client->hw_params.period_count); prtd->lsm_client->out_hw_params.period_count); return -EINVAL; } cmd_read.buf_addr_lsw = Loading Loading @@ -165,7 +165,7 @@ static int lsm_lab_buffer_sanity(struct lsm_priv *prtd, prtd->lsm_client->lab_buffer); return -EINVAL; } for (i = 0; i < prtd->lsm_client->hw_params.period_count; i++) { for (i = 0; i < prtd->lsm_client->out_hw_params.period_count; i++) { if ((lower_32_bits(prtd->lsm_client->lab_buffer[i].phys) == read_done->buf_addr_lsw) && (msm_audio_populate_upper_32_bits Loading Loading @@ -240,11 +240,11 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, "%s: process read done index %d\n", __func__, buf_index); if (buf_index >= prtd->lsm_client->hw_params.period_count) { prtd->lsm_client->out_hw_params.period_count) { dev_err(rtd->dev, "%s: Invalid index %d buf_index max cnt %d\n", __func__, buf_index, prtd->lsm_client->hw_params.period_count); prtd->lsm_client->out_hw_params.period_count); return; } prtd->dma_write += read_done->total_size; Loading @@ -253,7 +253,7 @@ static void lsm_event_handler(uint32_t opcode, uint32_t token, wake_up(&prtd->period_wait); /* queue the next period buffer */ buf_index = (buf_index + 1) % prtd->lsm_client->hw_params.period_count; prtd->lsm_client->out_hw_params.period_count; rc = msm_lsm_queue_lab_buffer(prtd, buf_index); if (rc) dev_err(rtd->dev, Loading Loading @@ -405,8 +405,8 @@ static int msm_lsm_lab_buffer_alloc(struct lsm_priv *lsm, int alloc) dma_buf->private_data = NULL; dma_buf->area = lsm->lsm_client->lab_buffer[0].data; dma_buf->addr = lsm->lsm_client->lab_buffer[0].phys; dma_buf->bytes = lsm->lsm_client->hw_params.buf_sz * lsm->lsm_client->hw_params.period_count; dma_buf->bytes = lsm->lsm_client->out_hw_params.buf_sz * lsm->lsm_client->out_hw_params.period_count; snd_pcm_set_runtime_buffer(lsm->substream, dma_buf); } else { ret = q6lsm_lab_buffer_alloc(lsm->lsm_client, alloc); Loading Loading @@ -1260,7 +1260,10 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, break; } case SNDRV_LSM_LAB_CONTROL: { u32 enable; struct lsm_hw_params *out_hw_params = &prtd->lsm_client->out_hw_params; u8 chmap[out_hw_params->num_chs]; u32 enable, ch_idx; if (copy_from_user(&enable, arg, sizeof(enable))) { dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n", Loading @@ -1270,7 +1273,14 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, dev_dbg(rtd->dev, "%s: ioctl %s, enable = %d\n", __func__, "SNDRV_LSM_LAB_CONTROL", enable); if (!prtd->lsm_client->started) { if (prtd->lsm_client->started) { dev_err(rtd->dev, "%s: ioctl %s issued after start", __func__, "SNDRV_LSM_LAB_CONTROL"); rc = -EINVAL; break; } if (prtd->lsm_client->lab_enable == enable) { dev_dbg(rtd->dev, "%s: Lab for session %d already %s\n", Loading @@ -1279,6 +1289,7 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, rc = 0; break; } rc = q6lsm_lab_control(prtd->lsm_client, enable); if (rc) { dev_err(rtd->dev, Loading @@ -1286,23 +1297,37 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, __func__, "SNDRV_LAB_CONTROL", rc, enable ? "enable" : "disable", prtd->lsm_client->session); } else { break; } rc = msm_lsm_lab_buffer_alloc(prtd, enable ? LAB_BUFFER_ALLOC : LAB_BUFFER_DEALLOC); if (rc) if (rc) { dev_err(rtd->dev, "%s: msm_lsm_lab_buffer_alloc failed rc %d for %s", __func__, rc, enable ? "ALLOC" : "DEALLOC"); if (!rc) prtd->lsm_client->lab_enable = enable; } } else { dev_err(rtd->dev, "%s: ioctl %s issued after start", __func__, "SNDRV_LSM_LAB_CONTROL"); rc = -EINVAL; break; } prtd->lsm_client->lab_enable = enable; memset(chmap, 0, out_hw_params->num_chs); /* * First channel to be read from lab is always the * best channel (0xff). For second channel onwards, * the channel indices are 0, 1, .. etc */ chmap[0] = 0xFF; for (ch_idx = 1; ch_idx < out_hw_params->num_chs; ch_idx++) chmap[ch_idx] = ch_idx - 1; rc = q6lsm_lab_out_ch_cfg(prtd->lsm_client, chmap); if (rc) dev_err(rtd->dev, "%s: Failed to set lab out ch cfg %d\n", __func__, rc); break; } case SNDRV_LSM_STOP_LAB: Loading Loading @@ -1354,6 +1379,23 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream, } break; } case SNDRV_LSM_SET_INPUT_HW_PARAMS: { struct lsm_hw_params *in_params; struct snd_lsm_input_hw_params params; if (copy_from_user(¶ms, arg, sizeof(params))) { dev_err(rtd->dev, "%s: %s: copy_from_user failed\n", __func__, "LSM_SET_INPUT_HW_PARAMS"); return -EFAULT; } in_params = &prtd->lsm_client->in_hw_params; in_params->sample_rate = params.sample_rate; in_params->sample_size = params.bit_width; in_params->num_chs = params.num_channels; break; } default: dev_dbg(rtd->dev, Loading Loading @@ -2241,7 +2283,7 @@ static int msm_lsm_prepare(struct snd_pcm_substream *substream) return -EINVAL; } if (q6lsm_set_media_fmt_params(prtd->lsm_client)) if (q6lsm_set_media_fmt_v2_params(prtd->lsm_client)) dev_dbg(rtd->dev, "%s: failed to set lsm media fmt params\n", __func__); Loading Loading @@ -2339,7 +2381,8 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; struct lsm_priv *prtd = runtime->private_data; struct lsm_hw_params *hw_params = NULL; struct lsm_hw_params *out_hw_params = NULL; struct lsm_hw_params *in_hw_params = NULL; struct snd_soc_pcm_runtime *rtd; if (!substream->private_data) { Loading @@ -2354,37 +2397,48 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, __func__, prtd, params); return -EINVAL; } hw_params = &prtd->lsm_client->hw_params; hw_params->num_chs = params_channels(params); hw_params->period_count = params_periods(params); hw_params->sample_rate = params_rate(params); if (((hw_params->sample_rate != 16000) && (hw_params->sample_rate != 48000)) || (hw_params->period_count == 0)) { in_hw_params = &prtd->lsm_client->in_hw_params; out_hw_params = &prtd->lsm_client->out_hw_params; out_hw_params->num_chs = params_channels(params); out_hw_params->period_count = params_periods(params); out_hw_params->sample_rate = params_rate(params); if (((out_hw_params->sample_rate != 16000) && (out_hw_params->sample_rate != 48000)) || (out_hw_params->period_count == 0)) { dev_err(rtd->dev, "%s: Invalid Params sample rate %d period count %d\n", __func__, hw_params->sample_rate, hw_params->period_count); __func__, out_hw_params->sample_rate, out_hw_params->period_count); return -EINVAL; } if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE) { hw_params->sample_size = 16; out_hw_params->sample_size = 16; } else if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE) { hw_params->sample_size = 24; out_hw_params->sample_size = 24; } else { dev_err(rtd->dev, "%s: Invalid Format 0x%x\n", __func__, params_format(params)); return -EINVAL; } hw_params->buf_sz = params_buffer_bytes(params) / hw_params->period_count; out_hw_params->buf_sz = params_buffer_bytes(params) / out_hw_params->period_count; dev_dbg(rtd->dev, "%s: channels %d sample rate %d sample size %d buffer size %d period count %d\n", __func__, hw_params->num_chs, hw_params->sample_rate, hw_params->sample_size, hw_params->buf_sz, hw_params->period_count); __func__, out_hw_params->num_chs, out_hw_params->sample_rate, out_hw_params->sample_size, out_hw_params->buf_sz, out_hw_params->period_count); /* * copy the out_hw_params to in_hw_params. in_hw_params will be * over-written with LSM_SET_INPUT_HW_PARAMS ioctl from userspace. * If this ioctl is not set, then it is assumed that input and * output hw params for LSM are the same. * Currently the period_count and buf_sz are unused for input params. */ memcpy(in_hw_params, out_hw_params, sizeof(struct lsm_hw_params)); return 0; } Loading Loading @@ -2456,7 +2510,7 @@ static int msm_lsm_pcm_copy(struct snd_pcm_substream *substream, int ch, return -EIO; } prtd->appl_cnt = prtd->appl_cnt % prtd->lsm_client->hw_params.period_count; prtd->lsm_client->out_hw_params.period_count; pcm_buf = prtd->lsm_client->lab_buffer[prtd->appl_cnt].data; dev_dbg(rtd->dev, "%s: copy the pcm data size %lu\n", Loading @@ -2474,7 +2528,7 @@ static int msm_lsm_pcm_copy(struct snd_pcm_substream *substream, int ch, return -EINVAL; } prtd->appl_cnt = (prtd->appl_cnt + 1) % prtd->lsm_client->hw_params.period_count; prtd->lsm_client->out_hw_params.period_count; atomic_dec(&prtd->buf_count); return 0; } Loading
dsp/q6lsm.c +157 −44 Original line number Diff line number Diff line Loading @@ -1028,38 +1028,33 @@ int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, } EXPORT_SYMBOL(q6lsm_set_fwk_mode_cfg); static int q6lsm_arrange_mch_map(struct lsm_param_media_fmt *media_fmt, int channel_count) static int q6lsm_arrange_mch_map(uint8_t *ch_map, int ch_cnt) { int rc = 0; int ch_idx; u8 mch_map[LSM_V3P0_MAX_NUM_CHANNELS] = { PCM_CHANNEL_FL, PCM_CHANNEL_FR, PCM_CHANNEL_FC, PCM_CHANNEL_LS, PCM_CHANNEL_RS, PCM_CHANNEL_LFE, PCM_CHANNEL_LB, PCM_CHANNEL_RB, PCM_CHANNEL_CS}; memset(media_fmt->channel_mapping, 0, LSM_MAX_NUM_CHANNELS); switch (channel_count) { case 1: media_fmt->channel_mapping[0] = PCM_CHANNEL_FC; break; case 2: media_fmt->channel_mapping[0] = PCM_CHANNEL_FL; media_fmt->channel_mapping[1] = PCM_CHANNEL_FR; break; case 3: media_fmt->channel_mapping[0] = PCM_CHANNEL_FL; media_fmt->channel_mapping[1] = PCM_CHANNEL_FR; media_fmt->channel_mapping[2] = PCM_CHANNEL_FC; break; case 4: media_fmt->channel_mapping[0] = PCM_CHANNEL_FL; media_fmt->channel_mapping[1] = PCM_CHANNEL_FR; media_fmt->channel_mapping[2] = PCM_CHANNEL_LS; media_fmt->channel_mapping[3] = PCM_CHANNEL_RS; break; default: pr_err("%s: invalid num_chan %d\n", __func__, channel_count); rc = -EINVAL; break; if (ch_cnt > LSM_V3P0_MAX_NUM_CHANNELS) { pr_err("%s: invalid num_chan %d\n", __func__, ch_cnt); return -EINVAL; } return rc; if (ch_cnt == 1) { ch_map[0] = PCM_CHANNEL_FC; } else if (ch_cnt == 4) { ch_map[0] = PCM_CHANNEL_FL; ch_map[1] = PCM_CHANNEL_FR; ch_map[2] = PCM_CHANNEL_LS; ch_map[3] = PCM_CHANNEL_RS; } else { for (ch_idx = 0; ch_idx < ch_cnt; ch_idx++) ch_map[ch_idx] = mch_map[ch_idx]; } return 0; } /** Loading @@ -1073,7 +1068,7 @@ static int q6lsm_arrange_mch_map(struct lsm_param_media_fmt *media_fmt, int q6lsm_set_media_fmt_params(struct lsm_client *client) { struct lsm_param_media_fmt media_fmt; struct lsm_hw_params param = client->hw_params; struct lsm_hw_params in_param = client->in_hw_params; struct param_hdr_v3 media_fmt_hdr; int rc = 0; Loading @@ -1091,10 +1086,11 @@ int q6lsm_set_media_fmt_params(struct lsm_client *client) media_fmt_hdr.param_size = sizeof(media_fmt); media_fmt.minor_version = QLSM_PARAM_ID_MINOR_VERSION_2; media_fmt.sample_rate = param.sample_rate; media_fmt.num_channels = param.num_chs; media_fmt.bit_width = param.sample_size; rc = q6lsm_arrange_mch_map(&media_fmt, media_fmt.num_channels); media_fmt.sample_rate = in_param.sample_rate; media_fmt.num_channels = in_param.num_chs; media_fmt.bit_width = in_param.sample_size; rc = q6lsm_arrange_mch_map(media_fmt.channel_mapping, media_fmt.num_channels); if (rc) goto err_ret; Loading @@ -1112,6 +1108,65 @@ int q6lsm_set_media_fmt_params(struct lsm_client *client) } EXPORT_SYMBOL(q6lsm_set_media_fmt_params); /* * q6lsm_set_media_fmt_v2_params - * command to set LSM media fmt (version2) params * * @client: LSM client handle * * Returns 0 on success or error on failure */ int q6lsm_set_media_fmt_v2_params(struct lsm_client *client) { u8 *param_buf; struct lsm_param_media_fmt_v2 *media_fmt_v2; struct lsm_hw_params *in_param = &client->in_hw_params; struct param_hdr_v3 media_fmt_v2_hdr; int param_len = 0, rc = 0; memset(&media_fmt_v2_hdr, 0, sizeof(media_fmt_v2_hdr)); param_len = sizeof(*media_fmt_v2) + (sizeof(uint8_t) * in_param->num_chs); /* Add padding to make sure total length is 4-byte aligned */ if (param_len % 4) param_len += (4 - (param_len % 4)); param_buf = kzalloc(param_len, GFP_KERNEL); if (!param_buf) return -ENOMEM; media_fmt_v2 = (struct lsm_param_media_fmt_v2 *) param_buf; media_fmt_v2->minor_version = QLSM_PARAM_ID_MINOR_VERSION; media_fmt_v2->sample_rate = in_param->sample_rate; media_fmt_v2->num_channels = in_param->num_chs; media_fmt_v2->bit_width = in_param->sample_size; rc = q6lsm_arrange_mch_map(media_fmt_v2->channel_mapping, in_param->num_chs); if (rc) goto err_mch_map; media_fmt_v2_hdr.module_id = LSM_MODULE_ID_FRAMEWORK; media_fmt_v2_hdr.instance_id = INSTANCE_ID_0; media_fmt_v2_hdr.param_id = LSM_PARAM_ID_MEDIA_FMT_V2; media_fmt_v2_hdr.param_size = param_len; pr_debug("%s: sample rate= %d, channels %d bit width %d\n", __func__, media_fmt_v2->sample_rate, media_fmt_v2->num_channels, media_fmt_v2->bit_width); rc = q6lsm_pack_and_set_params(client, &media_fmt_v2_hdr, param_buf, LSM_SESSION_CMD_SET_PARAMS_V2); if (rc) pr_err("%s: Failed set_params, rc %d\n", __func__, rc); err_mch_map: kfree(param_buf); return rc; } EXPORT_SYMBOL(q6lsm_set_media_fmt_v2_params); /** * q6lsm_set_data - * Command to set LSM data Loading Loading @@ -2051,6 +2106,62 @@ int q6lsm_lab_control(struct lsm_client *client, u32 enable) } EXPORT_SYMBOL(q6lsm_lab_control); /* * q6lsm_lab_out_ch_cfg - * Command to set the channel configuration * for look-ahead buffer. * * @client: LSM client handle * @ch_map: Channel map indicating the order * of channels to be configured. * * Returns 0 on success or error on failure */ int q6lsm_lab_out_ch_cfg(struct lsm_client *client, u8 *ch_map) { u8 *param_buf; struct lsm_param_lab_out_ch_cfg *lab_out_cfg; struct param_hdr_v3 lab_out_cfg_hdr; struct lsm_hw_params *out_params = &client->out_hw_params; int i, rc = 0, param_len = 0; param_len = sizeof(*lab_out_cfg) + sizeof(u8) * out_params->num_chs; if (param_len % 4) param_len += (4 - (param_len % 4)); param_buf = kzalloc(param_len, GFP_KERNEL); if (!param_buf) return -ENOMEM; lab_out_cfg = (struct lsm_param_lab_out_ch_cfg *) param_buf; lab_out_cfg->minor_version = QLSM_PARAM_ID_MINOR_VERSION; lab_out_cfg->num_channels = out_params->num_chs; for (i = 0; i < out_params->num_chs; i++) lab_out_cfg->channel_indices[i] = ch_map[i]; memset(&lab_out_cfg_hdr, 0, sizeof(lab_out_cfg_hdr)); lab_out_cfg_hdr.module_id = LSM_MODULE_ID_LAB; lab_out_cfg_hdr.instance_id = INSTANCE_ID_0; lab_out_cfg_hdr.param_id = LSM_PARAM_ID_LAB_OUTPUT_CHANNEL_CONFIG; lab_out_cfg_hdr.param_size = param_len; rc = q6lsm_pack_and_set_params(client, &lab_out_cfg_hdr, param_buf, LSM_SESSION_CMD_SET_PARAMS_V2); if (rc) pr_err("%s: Lab out channel config failed %d\n", __func__, rc); kfree(param_buf); return rc; } EXPORT_SYMBOL(q6lsm_lab_out_ch_cfg); /** * q6lsm_stop_lab - * command to stop LSM LAB Loading Loading @@ -2117,6 +2228,7 @@ int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc) { int ret = 0, i = 0; size_t allocate_size = 0, len = 0; struct lsm_hw_params *out_params = &client->out_hw_params; if (!client) { pr_err("%s: invalid client\n", __func__); Loading @@ -2126,20 +2238,20 @@ int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc) if (client->lab_buffer) { pr_err("%s: buffers are allocated period count %d period size %d\n", __func__, client->hw_params.period_count, client->hw_params.buf_sz); out_params->period_count, out_params->buf_sz); return -EINVAL; } allocate_size = client->hw_params.period_count * client->hw_params.buf_sz; allocate_size = out_params->period_count * out_params->buf_sz; allocate_size = PAGE_ALIGN(allocate_size); client->lab_buffer = kzalloc(sizeof(struct lsm_lab_buffer) * client->hw_params.period_count, GFP_KERNEL); out_params->period_count, GFP_KERNEL); if (!client->lab_buffer) { pr_err("%s: memory allocation for lab buffer failed count %d\n" , __func__, client->hw_params.period_count); out_params->period_count); return -ENOMEM; } ret = msm_audio_ion_alloc(&client->lab_buffer[0].dma_buf, Loading Loading @@ -2170,16 +2282,17 @@ int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc) __func__, client->lab_buffer[0].mem_map_handle, &client->lab_buffer[0].phys, client->hw_params.buf_sz); for (i = 0; i < client->hw_params.period_count; i++) { out_params->buf_sz); for (i = 0; i < out_params->period_count; i++) { client->lab_buffer[i].phys = client->lab_buffer[0].phys + (i * client->hw_params.buf_sz); (i * out_params->buf_sz); client->lab_buffer[i].size = client->hw_params.buf_sz; out_params->buf_sz; client->lab_buffer[i].data = (u8 *)(client->lab_buffer[0].data) + (i * client->hw_params.buf_sz); (i * out_params->buf_sz); client->lab_buffer[i].mem_map_handle = client->lab_buffer[0].mem_map_handle; } Loading
include/dsp/apr_audio-v2.h +2 −0 Original line number Diff line number Diff line Loading @@ -9951,6 +9951,8 @@ struct avcs_fwk_ver_info { #define LSM_PARAM_ID_POLLING_ENABLE (0x00012C1B) #define LSM_PARAM_ID_MEDIA_FMT (0x00012C1E) #define LSM_PARAM_ID_FWK_MODE_CONFIG (0x00012C27) #define LSM_PARAM_ID_MEDIA_FMT_V2 (0x00012C32) #define LSM_PARAM_ID_LAB_OUTPUT_CHANNEL_CONFIG (0x00012C2D) /* HW MAD specific */ #define AFE_MODULE_HW_MAD (0x00010230) Loading
include/dsp/q6lsm.h +20 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #define ADM_LSM_PORT_ID 0xADCB #define LSM_MAX_NUM_CHANNELS 8 #define LSM_V3P0_MAX_NUM_CHANNELS 9 typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv); Loading Loading @@ -82,7 +83,8 @@ struct lsm_client { bool lab_enable; bool lab_started; struct lsm_lab_buffer *lab_buffer; struct lsm_hw_params hw_params; struct lsm_hw_params out_hw_params; struct lsm_hw_params in_hw_params; bool use_topology; int session_state; bool poll_enable; Loading Loading @@ -157,6 +159,15 @@ struct lsm_param_media_fmt { uint8_t channel_mapping[LSM_MAX_NUM_CHANNELS]; } __packed; struct lsm_param_media_fmt_v2 { uint32_t minor_version; uint32_t sample_rate; uint16_t bit_width; uint16_t num_channels; uint8_t channel_mapping[0]; } __packed; struct lsm_param_confidence_levels { uint8_t num_confidence_levels; uint8_t confidence_levels[0]; Loading Loading @@ -192,6 +203,12 @@ struct lsm_param_lab_config { uint32_t wake_up_latency_ms; } __packed; struct lsm_param_lab_out_ch_cfg { uint32_t minor_version; uint32_t num_channels; uint8_t channel_indices[0]; } __packed; struct lsm_cmd_read { struct apr_hdr hdr; uint32_t buf_addr_lsw; Loading Loading @@ -250,4 +267,6 @@ void q6lsm_sm_set_param_data(struct lsm_client *client, int q6lsm_set_port_connected(struct lsm_client *client); int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, uint32_t event_mode); int q6lsm_set_media_fmt_params(struct lsm_client *client); int q6lsm_set_media_fmt_v2_params(struct lsm_client *client); int q6lsm_lab_out_ch_cfg(struct lsm_client *client, u8 *ch_map); #endif /* __Q6LSM_H__ */