| /* SPDX-License-Identifier: GPL-2.0-only */ |
| /* |
| * Google Whitechapel AoC ALSA Driver |
| * |
| * Copyright (c) 2019 Google LLC |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| */ |
| |
| #ifndef AOC_ALSA_H |
| #define AOC_ALSA_H |
| |
| #include <linux/device.h> |
| #include <linux/list.h> |
| #include <linux/interrupt.h> |
| #include <linux/wait.h> |
| #include <sound/core.h> |
| #include <sound/pcm.h> |
| #include <sound/pcm_params.h> |
| #include <sound/control.h> |
| #include <sound/jack.h> |
| #include <sound/soc.h> |
| #include <linux/version.h> |
| |
| #include <sound/compress_params.h> |
| #include <sound/compress_offload.h> |
| #include <sound/compress_driver.h> |
| |
| #include "../aoc-interface.h" |
| #include "google-aoc-enum.h" |
| |
| #define ALSA_AOC_CMD "alsa-aoc" |
| #define CMD_INPUT_CHANNEL "audio_input_control" |
| #define CMD_OUTPUT_CHANNEL "audio_output_control" |
| #define CMD_CHANNEL(_dev) \ |
| (strcmp(dev_name(&(_dev)->dev), CMD_INPUT_CHANNEL)) ? "output" : "input" |
| |
| #define AOC_MMAP_PLAYBACK_SERVICE "audio_playback0" |
| #define AOC_MMAP_CAPTURE_SERVICE "audio_capture1" |
| #define AOC_COMPR_OFFLOAD_SERVICE "audio_playback6" |
| #define AOC_COMPR_OFFLOAD_EOF_SERVICE "decoder_eof" |
| |
| enum uc_device_id { |
| UC_AUDIO_RECORD = 8, |
| UC_MMAP_RECORD = 9, |
| UC_LOW_LATENCY_AUDIO_RECORD = 10, |
| UC_ULTRASONIC_RECORD = 12 |
| }; |
| |
| #define AOC_AUDIO_CAPUTRE_DEVICE_MASK \ |
| (1 << UC_AUDIO_RECORD | 1 << UC_MMAP_RECORD | 1 << UC_LOW_LATENCY_AUDIO_RECORD) |
| |
| #define AOC_ULTRASONIC_CAPUTRE_DEVICE_MASK (1 << UC_ULTRASONIC_RECORD) |
| |
| #define AOC_CAPUTRE_DEVICE_MASK (AOC_AUDIO_CAPUTRE_DEVICE_MASK | AOC_ULTRASONIC_CAPUTRE_DEVICE_MASK) |
| |
| #define AOC_CMD_DEBUG_ENABLE |
| #define WAITING_TIME_MS 500 |
| |
| #define PCM_TIMER_INTERVAL_NANOSECS 10e6 |
| #define COMPR_OFFLOAD_TIMER_INTERVAL_NANOSECS 5000e6 |
| #define AOC_COMPR_HRTIMER_IRQ_HANDLER_BYPASS |
| #define DEFAULT_PCM_WAIT_TIME_IN_MSECS 10000 |
| #define DEFAULT_VOICE_PCM_WAIT_TIME_IN_MSECS 500 |
| #define COMPR_OFFLOAD_GAIN_RESET_TIME_DELAY_IN_MSECS 150 |
| #define COMPR_INVALID_METADATA (-1) |
| |
| /* Default mic and sink for audio capturing/playback */ |
| #define DEFAULT_MICPHONE_ID 0 |
| #define NUM_OF_BUILTIN_MIC 4 |
| #define DEFAULT_AUDIO_SINK_ID 0 |
| #define MAX_NUM_OF_SINKS_PER_STREAM 2 |
| |
| #define MAX_NUM_OF_INCALL_CAPTURE_STREAM 3 |
| |
| #define N_MIC_IN_SPATIAL_MODULE 3 |
| |
| /* TODO: the exact number has to be determined based on hardware platform*/ |
| #define MAX_NUM_OF_SUBSTREAMS 32 |
| #define MAX_NUM_OF_SINKS 5 |
| #define AVAIL_SUBSTREAMS_MASK 0x0fff |
| |
| #define AOC_AUDIO_SINK_BLOCK_ID_BASE 16 |
| #define AOC_COMPR_OFFLOAD_DEFAULT_SR 48000 |
| #define COMPR_OFFLOAD_KERNEL_TMP_BUF_SIZE PAGE_SIZE |
| |
| /* TODO: may not needed*/ |
| #define PLAYBACK_WATERMARK_DEFAULT 48000 |
| |
| #define MIC_HW_GAIN_IN_CB_MIN -720 |
| #define MIC_HW_GAIN_IN_CB_MAX 240 |
| |
| #define SIDETONE_EQ_STAGE_NUM_MIN 1 |
| #define SIDETONE_EQ_STAGE_NUM_MAX 5 |
| #define SIDETONE_VOL_MIN -96 |
| #define SIDETONE_VOL_MAX 0 |
| #define SIDETONE_MIC_ID_MIN 0 |
| #define SIDETONE_MIC_ID_MAX 3 |
| #define SIDETONE_BIQUAD_PARAM_NUM 6 |
| #define SIDETONE_BIQUAD_PARAM_MIN S32_MIN |
| #define SIDETONE_BIQUAD_PARAM_MAX S32_MAX |
| |
| #define FLOAT_ZERO 0x00000000 |
| #define FLOAT_ONE 0x3f800000 |
| |
| #define alsa2chip(vol) (vol) /* Convert alsa to chip volume */ |
| #define chip2alsa(vol) (vol) /* Convert chip to alsa volume */ |
| |
| #define NULL_PATH -1 |
| |
| /* Define trigger aoc watchdog reason */ |
| #define ALSA_CTL_TIMEOUT "alsa_ctl_timeout" |
| |
| /* TODO: Copied from AoC repo and will be removed */ |
| enum bluetooth_mode { |
| AHS_BT_MODE_UNCONFIGURED = 0, |
| AHS_BT_MODE_SCO, |
| AHS_BT_MODE_ESCO, |
| AHS_BT_MODE_A2DP_RAW, |
| AHS_BT_MODE_A2DP_ENC_SBC, |
| AHS_BT_MODE_A2DP_ENC_AAC, |
| AHS_BT_MODE_A2DP_ENC_LC3, |
| AHS_BT_MODE_BLE_ENC_LC3, |
| AHS_BT_MODE_BLE_CONVERSATION, |
| AHS_BT_MODE_A2DP_ENC_OPUS, |
| }; |
| |
| enum TelephonyModes { |
| AHS_TELE_MODE_MODEM, |
| AHS_TELE_MODE_VOIP_48, |
| AHS_TELE_MODE_VOIP_44, |
| AHS_TELE_MODE_VOIP_32, |
| AHS_TELE_MODE_VOIP_24, |
| AHS_TELE_MODE_VOIP_16, |
| AHS_TELE_MODE_VOIP_8, |
| }; |
| |
| /* AoC USB Config parameters */ |
| enum { |
| USB_BUS_ID, |
| USB_DEV_ID, |
| USB_TX_EP_ID, |
| USB_TX_FORMAT, |
| USB_TX_SR, |
| USB_TX_CH, |
| USB_TX_BW, |
| USB_RX_EP_ID, |
| USB_RX_FORMAT, |
| USB_RX_SR, |
| USB_RX_CH, |
| USB_RX_BW, |
| USB_CFG_TO_AOC |
| }; |
| |
| /* AoC sidetone EQ */ |
| enum { BIQUAD0 = 0, BIQUAD1, BIQUAD2, BIQUAD3, BIQUAD4, SIDETONE_EQ_BIQUAD_NUM }; |
| enum { SIDETONE_CFG_VOL, SIDETONE_CFG_STAGE_NUM, SIDETONE_CFG_MIC_ID }; |
| |
| enum { CTRL_VOL_MUTE, CTRL_VOL_UNMUTE }; |
| enum { |
| PCM_PLAYBACK_VOLUME, |
| PCM_PLAYBACK_MUTE, |
| BUILDIN_MIC_POWER_STATE, |
| BUILDIN_MIC_CAPTURE_LIST, |
| BUILDIN_US_MIC_CAPTURE_LIST, |
| A2DP_ENCODER_PARAMETERS, |
| }; |
| |
| enum aoc_playback_entry_point { |
| ULL = 0, |
| LL0, |
| LL1, |
| LL2, |
| LL3, |
| DEEP_BUFFER, |
| OFF_LOAD, |
| HAPTICS = 10, |
| SIDETONE = 11, |
| USB_HIFI = 13, |
| SPEAKER_US = 14, |
| IMMERSIVE = 15, |
| }; |
| |
| enum { NORMAL = 0, MMAPED, RAW, INCALL, HIFI, ANDROID_AEC, COMPRESS }; |
| |
| enum { BUILTIN_MIC0 = 0, BUILTIN_MIC1, BUILTIN_MIC2, BUILTIN_MIC3 }; |
| enum { MIC_LOW_POWER_GAIN = 0, MIC_HIGH_POWER_GAIN, MIC_CURRENT_GAIN }; |
| enum { DEFAULT_MIC = 0, BUILTIN_MIC, USB_MIC, BT_MIC, IN_CALL_MUSIC, NO_MIC=IN_CALL_MUSIC, ERASER }; |
| enum aec_ref_source { |
| DEFAULT_PLAYBACK = 0, |
| SPEAKER_PLAYBACK, |
| USB_PLAYBACK, |
| BT_PLAYBACK, |
| NUM_AEC_REF_SOURCE |
| }; |
| enum { INCALL_CAPTURE_OFF = 0, INCALL_CAPTURE_UL, INCALL_CAPTURE_DL, INCALL_CAPTURE_UL_DL }; |
| enum { NONBLOCKING = 0, BLOCKING = 1 }; |
| enum { STOP = 0, START }; |
| enum { PLAYBACK_MODE, VOICE_TX_MODE, VOICE_RX_MODE, HAPTICS_MODE, OFFLOAD_MODE }; |
| |
| struct aoc_chip { |
| struct snd_card *card; |
| struct snd_soc_jack jack; /* TODO: temporary use, need refactor */ |
| |
| uint32_t avail_substreams; |
| struct aoc_alsa_stream *alsa_stream[MAX_NUM_OF_SUBSTREAMS]; |
| |
| struct aoc_service_dev *dev_alsa_stream[MAX_NUM_OF_SUBSTREAMS]; |
| |
| int default_mic_id; |
| int buildin_mic_id_list[NUM_OF_BUILTIN_MIC]; |
| int buildin_us_mic_id_list[NUM_OF_BUILTIN_MIC]; |
| |
| int default_sink_id; |
| int sink_id_list[MAX_NUM_OF_SINKS_PER_STREAM]; |
| int sink_mode[AUDIO_OUTPUT_SINKS]; |
| |
| int volume; |
| int old_volume; /* Store the volume value while muted */ |
| int mute; |
| int audio_capture_mic_source; |
| int voice_call_mic_source; |
| enum aec_ref_source ft_aec_ref_source; |
| enum aec_ref_source eraser_aec_ref_source; |
| int voice_call_mic_mute; |
| int default_mic_hw_gain; |
| int voice_call_audio_enable; |
| int incall_capture_state[MAX_NUM_OF_INCALL_CAPTURE_STREAM]; |
| |
| int telephony_curr_mic; |
| int telephony_curr_sink; |
| int telephony_expect_mic; |
| int telephony_expect_sink; |
| bool voip_rx_prepared; |
| bool voip_tx_prepared; |
| bool voip_path_vote[PORT_MAX]; |
| bool voice_path_vote[PORT_MAX]; |
| struct wakeup_source *wakelock; |
| |
| int compr_offload_volume; |
| int mic_spatial_module_enable; |
| int capture_eraser_enable; |
| int sidetone_enable; |
| int mic_loopback_enabled; |
| int gapless_offload_enable; |
| unsigned int opened; |
| unsigned int capture_param_set; |
| struct mutex audio_mutex; |
| struct mutex audio_cmd_chan_mutex; |
| spinlock_t audio_lock; |
| long pcm_wait_time_in_ms; |
| long voice_pcm_wait_time_in_ms; |
| |
| struct AUDIO_OUTPUT_BT_A2DP_ENC_CFG a2dp_encoder_cfg; |
| struct CMD_AUDIO_OUTPUT_USB_CONFIG usb_sink_cfg; |
| struct CMD_AUDIO_OUTPUT_USB_CONFIG_V2 usb_sink_cfg_v2; |
| struct CMD_AUDIO_OUTPUT_GET_SIDETONE sidetone_cfg; |
| }; |
| |
| struct aoc_alsa_stream { |
| struct aoc_chip *chip; |
| struct snd_pcm_substream *substream; |
| struct snd_compr_stream *cstream; /* compress offload stream */ |
| int compr_offload_codec; |
| int gapless_offload_enable; |
| int send_metadata; |
| int eof_reach; |
| uint32_t compr_padding; |
| uint32_t compr_delay; |
| uint64_t compr_pcm_io_sample_base; |
| int offload_temp_data_buf_size; |
| struct timer_list timer; /* For advancing the hw ptr */ |
| struct hrtimer hr_timer; /* For advancing the hw ptr */ |
| unsigned long timer_interval_ns; |
| |
| struct aoc_service_dev *dev; |
| struct aoc_service_dev *dev_eof; /* Aoc service for EOF in compr offload */ |
| int idx; /* PCM device number */ |
| int entry_point_idx; /* Index of entry point, same as idx in playback */ |
| int stream_type; /* Normal pcm, incall, mmap, hifi, compr */ |
| |
| int channels; /* Number of channels in audio */ |
| int params_rate; /* Sampling rate */ |
| int pcm_format_width; /* Number of bits */ |
| bool pcm_float_fmt; /* Floating point */ |
| |
| struct vm_area_struct *vma; /* for MMAP */ |
| unsigned int period_size; |
| unsigned int buffer_size; |
| unsigned int pos; |
| unsigned long hw_ptr_base; /* read/write pointers in ring buffer */ |
| unsigned long prev_consumed; |
| int n_overflow; |
| int open; |
| int running; |
| int draining; |
| |
| struct work_struct free_aoc_service_work; |
| struct work_struct pcm_period_work; |
| }; |
| |
| void aoc_timer_start(struct aoc_alsa_stream *alsa_stream); |
| void aoc_timer_restart(struct aoc_alsa_stream *alsa_stream); |
| void aoc_timer_stop(struct aoc_alsa_stream *alsa_stream); |
| void aoc_timer_stop_sync(struct aoc_alsa_stream *alsa_stream); |
| void aoc_pcm_period_work_handler(struct work_struct *work); |
| |
| int snd_aoc_new_ctl(struct aoc_chip *chip); |
| int snd_aoc_new_pcm(struct aoc_chip *chip); |
| |
| int aoc_audio_setup(struct aoc_alsa_stream *alsa_stream); |
| int aoc_audio_open(struct aoc_alsa_stream *alsa_stream); |
| int aoc_audio_close(struct aoc_alsa_stream *alsa_stream); |
| int aoc_audio_set_params(struct aoc_alsa_stream *alsa_stream, uint32_t channels, |
| uint32_t samplerate, uint32_t bps, bool pcm_float_fmt, int source_mode); |
| |
| int aoc_audio_start(struct aoc_alsa_stream *alsa_stream); |
| int aoc_audio_stop(struct aoc_alsa_stream *alsa_stream); |
| int aoc_audio_incall_start(struct aoc_alsa_stream *alsa_stream); |
| int aoc_audio_incall_stop(struct aoc_alsa_stream *alsa_stream); |
| int aoc_audio_voip_start(struct aoc_alsa_stream *alsa_stream); |
| int aoc_audio_voip_stop(struct aoc_alsa_stream *alsa_stream); |
| |
| int aoc_pcm_device_to_stream_type(int device); |
| |
| int aoc_audio_path_open(struct aoc_chip *chip, int src, int dest, bool be_on); |
| int aoc_audio_path_close(struct aoc_chip *chip, int src, int dest, bool be_on); |
| int aoc_phonecall_path_open(struct aoc_chip *chip, int src, int dst, bool capture); |
| int aoc_phonecall_path_close(struct aoc_chip *chip, int src, int dst, bool capture); |
| int aoc_voipcall_path_open(struct aoc_chip *chip, int src, int dst, bool capture); |
| int aoc_voipcall_path_close(struct aoc_chip *chip, int src, int dst, bool capture); |
| |
| int aoc_audio_set_ctls(struct aoc_chip *chip); |
| |
| int aoc_a2dp_get_enc_param_size(void); |
| int aoc_a2dp_set_enc_param(struct aoc_chip *chip, struct AUDIO_OUTPUT_BT_A2DP_ENC_CFG *cfg); |
| |
| int aoc_set_builtin_mic_power_state(struct aoc_chip *chip, int iMic, int state); |
| int aoc_get_builtin_mic_power_state(struct aoc_chip *chip, int iMic); |
| int aoc_mic_clock_rate_get(struct aoc_chip *chip); |
| int aoc_mic_hw_gain_get(struct aoc_chip *chip, int state); |
| int aoc_mic_hw_gain_set(struct aoc_chip *chip, int state, int gain); |
| int aoc_mic_dc_blocker_get(struct aoc_chip *chip); |
| int aoc_mic_dc_blocker_set(struct aoc_chip *chip, int enable); |
| |
| int aoc_mic_record_gain_get(struct aoc_chip *chip, long *val); |
| int aoc_mic_record_gain_set(struct aoc_chip *chip, long val); |
| int aoc_mmap_record_gain_get(struct aoc_chip *chip, long *val); |
| int aoc_mmap_record_gain_set(struct aoc_chip *chip, long val); |
| int aoc_audio_capture_mic_prepare(struct aoc_chip *chip); |
| int aoc_audio_capture_mic_close(struct aoc_chip *chip); |
| int aoc_audio_capture_active_stream_num(struct aoc_chip *chip); |
| int ap_data_control_trigger(struct aoc_chip *chip, struct aoc_alsa_stream *alsa_stream, |
| int record_cmd); |
| int ap_record_stop(struct aoc_chip *chip, struct aoc_alsa_stream *alsa_stream); |
| int aoc_capture_filter_runtime_control(struct aoc_chip *chip, uint32_t port_id, bool on); |
| int aoc_audio_capture_runtime_trigger(struct aoc_chip *chip, int ep_id, int dst, bool on); |
| int aoc_audio_capture_eraser_enable(struct aoc_chip *chip, long enable); |
| int aoc_eraser_aec_reference_set(struct aoc_chip *chip, long ref_source); |
| |
| int aoc_voice_call_mic_mute(struct aoc_chip *chip, int mute); |
| int aoc_incall_capture_enable_get(struct aoc_chip *chip, int stream, long *val); |
| int aoc_incall_capture_enable_set(struct aoc_chip *chip, int stream, long val); |
| int aoc_incall_playback_enable_get(struct aoc_chip *chip, int stream, long *val); |
| int aoc_incall_playback_enable_set(struct aoc_chip *chip, int stream, long val); |
| int aoc_incall_playback_mic_channel_get(struct aoc_chip *chip, int stream, long *val); |
| int aoc_incall_playback_mic_channel_set(struct aoc_chip *chip, int stream, long val); |
| int aoc_incall_mic_sink_mute_get(struct aoc_chip *chip, int param, long *mute); |
| int aoc_incall_mic_sink_mute_set(struct aoc_chip *chip, int param, long mute); |
| |
| int aoc_lvm_enable_get(struct aoc_chip *chip, long *enable); |
| int aoc_lvm_enable_set(struct aoc_chip *chip, long enable); |
| int aoc_decoder_ref_enable_get(struct aoc_chip *chip, long*enable); |
| int aoc_decoder_ref_enable_set(struct aoc_chip *chip, long enable); |
| |
| |
| int aoc_sidetone_enable(struct aoc_chip *chip, int enable); |
| int aoc_sidetone_cfg_get(struct aoc_chip *chip, int param, long *val); |
| int aoc_sidetone_cfg_set(struct aoc_chip *chip, int param, long val); |
| int aoc_sidetone_eq_get(struct aoc_chip *chip, int biquad_idx, long *val); |
| int aoc_sidetone_eq_set(struct aoc_chip *chip, int biquad_idx, long *val); |
| |
| int aoc_get_dsp_state(struct aoc_chip *chip); |
| int aoc_get_asp_mode(struct aoc_chip *chip, int block, int component, int key); |
| int aoc_set_asp_mode(struct aoc_chip *chip, int block, int component, int key, int val); |
| |
| int aoc_get_audio_dsp_mode(struct aoc_chip *chip, long *val); |
| int aoc_set_audio_dsp_mode(struct aoc_chip *chip, long val); |
| |
| int aoc_get_builtin_mic_process_mode(struct aoc_chip *chip); |
| int aoc_set_builtin_mic_process_mode(struct aoc_chip *chip, long mode); |
| |
| int aoc_spatial_module_start(struct aoc_chip *chip); |
| int aoc_spatial_module_stop(struct aoc_chip *chip); |
| |
| int aoc_get_sink_state(struct aoc_chip *chip, int sink); |
| int aoc_get_sink_channel_bitmap(struct aoc_chip *chip, int sink); |
| int aoc_get_sink_mode(struct aoc_chip *chip, int sink); |
| int aoc_set_sink_mode(struct aoc_chip *chip, int sink, int mode); |
| |
| int aoc_set_usb_config(struct aoc_chip *chip); |
| int aoc_set_usb_config_v2(struct aoc_chip *chip); |
| |
| int aoc_audio_write(struct aoc_alsa_stream *alsa_stream, void *src, |
| uint32_t count); |
| int aoc_audio_read(struct aoc_alsa_stream *alsa_stream, void *dest, |
| uint32_t count); |
| int aoc_audio_volume_set(struct aoc_chip *chip, uint32_t volume, |
| int src, int dst); |
| |
| int prepare_phonecall(struct aoc_alsa_stream *alsa_stream); |
| int teardown_phonecall(struct aoc_alsa_stream *alsa_stream); |
| |
| int prepare_voipcall(struct aoc_alsa_stream *alsa_stream); |
| int teardown_voipcall(struct aoc_alsa_stream *alsa_stream); |
| |
| void aoc_compr_offload_isr(struct aoc_service_dev *dev); |
| int aoc_compr_offload_setup(struct aoc_alsa_stream *alsa_stream, int type); |
| int aoc_compr_offload_send_metadata(struct aoc_alsa_stream *alsa_stream); |
| int aoc_compr_offload_partial_drain(struct aoc_alsa_stream *alsa_stream); |
| int aoc_compr_offload_close(struct aoc_alsa_stream *alsa_stream); |
| int aoc_compr_offload_get_io_samples(struct aoc_alsa_stream *alsa_stream, uint64_t *sample); |
| int aoc_compr_offload_flush_buffer(struct aoc_alsa_stream *alsa_stream); |
| int aoc_compr_pause(struct aoc_alsa_stream *alsa_stream); |
| int aoc_compr_resume(struct aoc_alsa_stream *alsa_stream); |
| int aoc_compr_offload_linear_gain_get(struct aoc_chip *chip, long *val); |
| int aoc_compr_offload_linear_gain_set(struct aoc_chip *chip, long *val); |
| |
| int aoc_mic_loopback(struct aoc_chip *chip, int enable); |
| |
| int aoc_pcm_init(void); |
| void aoc_pcm_exit(void); |
| int aoc_voice_init(void); |
| void aoc_voice_exit(void); |
| int aoc_compr_init(void); |
| void aoc_compr_exit(void); |
| int aoc_path_init(void); |
| void aoc_path_exit(void); |
| int aoc_nohost_init(void); |
| void aoc_nohost_exit(void); |
| int aoc_incall_init(void); |
| void aoc_incall_exit(void); |
| int aoc_voip_init(void); |
| void aoc_voip_exit(void); |
| |
| int aoc_audio_us_record(struct aoc_chip *chip, bool enable); |
| #endif |