Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | // |
| 3 | // ASoC simple sound card support |
| 4 | // |
| 5 | // Copyright (C) 2012 Renesas Solutions Corp. |
| 6 | // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 7 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 8 | //#define DEBUG |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 9 | #include <linux/clk.h> |
| 10 | #include <linux/device.h> |
| 11 | #include <linux/gpio.h> |
| 12 | #include <linux/module.h> |
| 13 | #include <linux/of.h> |
| 14 | #include <linux/of_gpio.h> |
| 15 | #include <linux/of_device.h> |
| 16 | #include <linux/platform_device.h> |
| 17 | #include <linux/string.h> |
| 18 | #include <linux/timer.h> |
| 19 | #include <linux/workqueue.h> |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 20 | //#include <linux/extcon.h> |
| 21 | #include <linux/extcon-provider.h> |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 22 | #include <sound/jack.h> |
| 23 | #include <sound/soc.h> |
| 24 | #include <sound/soc-dai.h> |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 25 | #include <sound/control.h> |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 26 | #include "card.h" |
| 27 | |
| 28 | #include "effects.h" |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 29 | #include "iomap.h" |
| 30 | #include "regs.h" |
| 31 | #include "../common/misc.h" |
| 32 | #include "../common/audio_uevent.h" |
| 33 | #include "audio_controller.h" |
| 34 | #ifdef CONFIG_AMLOGIC_MEDIA_VIDEO |
| 35 | #include <linux/amlogic/media/video_sink/video.h> |
| 36 | #endif |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 37 | |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 38 | /*the same as audio hal type define!*/ |
| 39 | static const char * const audio_format[] = { |
| 40 | "PCM", |
| 41 | "DTS_EXPRESS", |
| 42 | "DOLBY_DIGITAL", |
| 43 | "DTS", |
| 44 | "DOLBY_DIGITAL_PLUS", |
| 45 | "DTS_HD", |
| 46 | "MULTI_CHANNEL PCM", |
| 47 | "DOLBY_TRUEHD", |
| 48 | "DTS_HD_MA", |
| 49 | "HIFI PCM", |
| 50 | "DOLBY_AC4", |
| 51 | "DOLBY_MAT", |
| 52 | "DOLBY_DDP_ATMOS", |
| 53 | "DOLBY_THD_ATMOS", |
| 54 | "DOLBY_MAT_ATMOS", |
| 55 | "DOLBY_AC4_ATMOS", |
| 56 | "DTS_HP", |
| 57 | "DOLBY_DDP_ATMOS_PROMPT_ON_ATMOS", |
| 58 | "DOLBY_THD_ATMOS_PROMPT_ON_ATMOS", |
| 59 | "DOLBY_MAT_ATMOS_PROMPT_ON_ATMOS", |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 60 | "DOLBY_AC4_ATMOS_PROMPT_ON_ATMOS", |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 61 | }; |
| 62 | |
| 63 | enum audio_hal_format { |
| 64 | TYPE_PCM = 0, |
| 65 | TYPE_DTS_EXPRESS = 1, |
| 66 | TYPE_AC3 = 2, |
| 67 | TYPE_DTS = 3, |
| 68 | TYPE_EAC3 = 4, |
| 69 | TYPE_DTS_HD = 5, |
| 70 | TYPE_MULTI_PCM = 6, |
| 71 | TYPE_TRUE_HD = 7, |
| 72 | TYPE_DTS_HD_MA = 8, |
| 73 | TYPE_PCM_HIGH_SR = 9, |
| 74 | TYPE_AC4 = 10, |
| 75 | TYPE_MAT = 11, |
| 76 | TYPE_DDP_ATMOS = 12, |
| 77 | TYPE_TRUE_HD_ATMOS = 13, |
| 78 | TYPE_MAT_ATMOS = 14, |
| 79 | TYPE_AC4_ATMOS = 15, |
| 80 | TYPE_DTS_HP = 16, |
| 81 | TYPE_DDP_ATMOS_PROMPT_ON_ATMOS = 17, |
| 82 | TYPE_TRUE_HD_ATMOS_PROMPT_ON_ATMOS = 18, |
| 83 | TYPE_MAT_ATMOS_PROMPT_ON_ATMOS = 19, |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 84 | TYPE_AC4_ATMOS_PROMPT_ON_ATMOS = 20, |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 85 | }; |
| 86 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 87 | struct aml_jack { |
| 88 | struct snd_soc_jack jack; |
| 89 | struct snd_soc_jack_pin pin; |
| 90 | struct snd_soc_jack_gpio gpio; |
| 91 | }; |
| 92 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 93 | struct aml_card_data { |
| 94 | struct snd_soc_card snd_card; |
| 95 | struct aml_dai_props { |
| 96 | /* sync with android audio hal, |
| 97 | * dai link is used for which output, |
| 98 | */ |
| 99 | const char *suffix_name; |
| 100 | |
| 101 | struct aml_dai cpu_dai; |
| 102 | struct aml_dai codec_dai; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 103 | struct snd_soc_dai_link_component cpus; /* single cpu */ |
| 104 | struct snd_soc_dai_link_component codecs; /* single codec */ |
| 105 | struct snd_soc_dai_link_component platforms; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 106 | unsigned int mclk_fs; |
| 107 | } *dai_props; |
| 108 | unsigned int mclk_fs; |
| 109 | struct aml_jack hp_jack; |
| 110 | struct aml_jack mic_jack; |
| 111 | struct snd_soc_dai_link *dai_link; |
| 112 | int spk_mute_gpio; |
| 113 | bool spk_mute_active_low; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 114 | bool spk_mute_flag; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 115 | struct gpio_desc *avout_mute_desc; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 116 | struct timer_list timer; |
| 117 | struct work_struct work; |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 118 | struct work_struct init_work; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 119 | int hp_last_state; |
| 120 | int hp_cur_state; |
| 121 | int hp_det_status; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 122 | int hp_gpio_det; |
| 123 | int hp_detect_flag; |
| 124 | bool hp_det_enable; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 125 | enum of_gpio_flags hp_det_flags; |
| 126 | int micphone_last_state; |
| 127 | int micphone_cur_state; |
| 128 | int micphone_det_status; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 129 | int micphone_gpio_det; |
| 130 | int mic_detect_flag; |
| 131 | bool mic_det_enable; |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 132 | bool av_mute_enable; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 133 | bool spk_mute_enable; |
| 134 | int irq_exception64; |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 135 | enum audio_hal_format hal_fmt; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 136 | }; |
| 137 | |
| 138 | #define aml_priv_to_dev(priv) ((priv)->snd_card.dev) |
| 139 | #define aml_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) |
| 140 | #define aml_priv_to_props(priv, i) ((priv)->dai_props + (i)) |
| 141 | #define aml_card_to_priv(card) \ |
| 142 | (container_of(card, struct aml_card_data, snd_card)) |
| 143 | |
| 144 | #define DAI "sound-dai" |
| 145 | #define CELL "#sound-dai-cells" |
| 146 | #define PREFIX "aml-audio-card," |
| 147 | |
| 148 | #define aml_card_init_hp(card, sjack, prefix)\ |
| 149 | aml_card_init_jack(card, sjack, 1, prefix) |
| 150 | #define aml_card_init_mic(card, sjack, prefix)\ |
| 151 | aml_card_init_jack(card, sjack, 0, prefix) |
| 152 | |
| 153 | static const unsigned int headphone_cable[] = { |
| 154 | EXTCON_JACK_HEADPHONE, |
| 155 | EXTCON_NONE, |
| 156 | }; |
| 157 | |
| 158 | static const unsigned int microphone_cable[] = { |
| 159 | EXTCON_JACK_MICROPHONE, |
| 160 | EXTCON_NONE, |
| 161 | }; |
| 162 | |
| 163 | struct extcon_dev *audio_extcon_headphone; |
| 164 | struct extcon_dev *audio_extcon_microphone; |
| 165 | |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 166 | static const struct soc_enum audio_hal_format_enum = |
| 167 | SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(audio_format), |
| 168 | audio_format); |
| 169 | |
| 170 | static int aml_audio_hal_format_get_enum(struct snd_kcontrol *kcontrol, |
| 171 | struct snd_ctl_elem_value *ucontrol) |
| 172 | { |
| 173 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); |
| 174 | struct aml_card_data *p_aml_audio; |
| 175 | |
| 176 | p_aml_audio = snd_soc_card_get_drvdata(card); |
| 177 | ucontrol->value.integer.value[0] = p_aml_audio->hal_fmt; |
| 178 | |
| 179 | return 0; |
| 180 | } |
| 181 | |
| 182 | static int aml_audio_hal_format_set_enum(struct snd_kcontrol *kcontrol, |
| 183 | struct snd_ctl_elem_value *ucontrol) |
| 184 | { |
| 185 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); |
| 186 | struct aml_card_data *p_aml_audio; |
| 187 | int hal_format = ucontrol->value.integer.value[0]; |
| 188 | |
| 189 | p_aml_audio = snd_soc_card_get_drvdata(card); |
| 190 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 191 | audio_send_uevent(card->dev, AUDIO_SPDIF_FMT_EVENT, hal_format); |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 192 | pr_info("update audio atmos flag! audio_type = %d\n", hal_format); |
| 193 | |
| 194 | if (p_aml_audio->hal_fmt != hal_format) |
| 195 | p_aml_audio->hal_fmt = hal_format; |
| 196 | |
| 197 | return 0; |
| 198 | } |
| 199 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 200 | static int aml_chip_id_get(struct snd_kcontrol *kcontrol, |
| 201 | struct snd_ctl_elem_value *ucontrol) |
| 202 | { |
| 203 | (void)kcontrol; |
| 204 | ucontrol->value.integer.value[0] = aml_return_chip_id(); |
| 205 | return 0; |
| 206 | } |
| 207 | |
| 208 | #ifdef CONFIG_AMLOGIC_MEDIA_VIDEO |
| 209 | static int aml_media_video_delay_get_enum(struct snd_kcontrol *kcontrol, |
| 210 | struct snd_ctl_elem_value *ucontrol) |
| 211 | { |
| 212 | (void)kcontrol; |
| 213 | ucontrol->value.integer.value[0] = get_playback_delay_duration(); |
| 214 | return 0; |
| 215 | } |
| 216 | #endif |
| 217 | |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 218 | static const struct snd_kcontrol_new snd_user_controls[] = { |
| 219 | SOC_ENUM_EXT("Audio HAL Format", |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 220 | audio_hal_format_enum, |
| 221 | aml_audio_hal_format_get_enum, |
| 222 | aml_audio_hal_format_set_enum), |
| 223 | |
| 224 | SND_SOC_BYTES_EXT("AML chip id", 1, |
| 225 | aml_chip_id_get, NULL), |
| 226 | |
| 227 | #ifdef CONFIG_AMLOGIC_MEDIA_VIDEO |
| 228 | SOC_SINGLE_EXT("Media Video Delay", |
| 229 | 0, 0, 0, 0, |
| 230 | aml_media_video_delay_get_enum, |
| 231 | NULL), |
| 232 | #endif |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 233 | }; |
| 234 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 235 | static void jack_audio_start_timer(struct aml_card_data *card_data, |
| 236 | unsigned long delay) |
| 237 | { |
| 238 | card_data->timer.expires = jiffies + delay; |
| 239 | add_timer(&card_data->timer); |
| 240 | } |
| 241 | |
| 242 | static void jack_audio_stop_timer(struct aml_card_data *card_data) |
| 243 | { |
| 244 | del_timer_sync(&card_data->timer); |
| 245 | cancel_work_sync(&card_data->work); |
| 246 | } |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 247 | |
| 248 | static void jack_timer_func(struct timer_list *t) |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 249 | { |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 250 | struct aml_card_data *card_data = from_timer(card_data, t, timer); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 251 | unsigned long delay = msecs_to_jiffies(150); |
| 252 | |
| 253 | schedule_work(&card_data->work); |
| 254 | mod_timer(&card_data->timer, jiffies + delay); |
| 255 | } |
| 256 | |
| 257 | static int jack_audio_hp_detect(struct aml_card_data *card_data) |
| 258 | { |
| 259 | int loop_num = 0; |
| 260 | int change_cnt = 0; |
| 261 | |
| 262 | card_data->hp_cur_state = |
| 263 | gpio_get_value_cansleep(card_data->hp_jack.gpio.gpio); |
| 264 | if (card_data->hp_last_state != card_data->hp_cur_state) { |
| 265 | while (loop_num < 5) { |
| 266 | card_data->hp_cur_state = |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 267 | gpio_get_value_cansleep(card_data->hp_jack.gpio.gpio); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 268 | |
| 269 | if (card_data->hp_last_state != card_data->hp_cur_state) |
| 270 | change_cnt++; |
| 271 | else |
| 272 | change_cnt = 0; |
| 273 | |
| 274 | msleep_interruptible(50); |
| 275 | loop_num = loop_num + 1; |
| 276 | } |
| 277 | if (change_cnt >= 5) { |
| 278 | card_data->hp_last_state = card_data->hp_cur_state; |
| 279 | card_data->hp_det_status = card_data->hp_last_state; |
| 280 | } |
| 281 | return card_data->hp_det_status; |
| 282 | } |
| 283 | return -1; |
| 284 | } |
| 285 | |
| 286 | static int jack_audio_micphone_detect(struct aml_card_data *card_data) |
| 287 | { |
| 288 | int loop_num = 0; |
| 289 | int change_cnt = 0; |
| 290 | |
| 291 | card_data->micphone_cur_state = |
| 292 | gpio_get_value_cansleep(card_data->mic_jack.gpio.gpio); |
| 293 | if (card_data->micphone_last_state != card_data->micphone_cur_state) { |
| 294 | while (loop_num < 5) { |
| 295 | card_data->micphone_cur_state = |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 296 | gpio_get_value_cansleep(card_data->mic_jack.gpio.gpio); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 297 | if (card_data->micphone_last_state != |
| 298 | card_data->micphone_cur_state) |
| 299 | change_cnt++; |
| 300 | else |
| 301 | change_cnt = 0; |
| 302 | |
| 303 | msleep_interruptible(50); |
| 304 | loop_num = loop_num + 1; |
| 305 | } |
| 306 | if (change_cnt >= 5) { |
| 307 | card_data->micphone_last_state = |
| 308 | card_data->micphone_cur_state; |
| 309 | card_data->micphone_det_status = |
| 310 | card_data->micphone_last_state; |
| 311 | } |
| 312 | return card_data->micphone_det_status; |
| 313 | } |
| 314 | return -1; |
| 315 | } |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 316 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 317 | static void jack_work_func(struct work_struct *work) |
| 318 | { |
| 319 | struct aml_card_data *card_data = NULL; |
| 320 | int status = SND_JACK_HEADPHONE; |
| 321 | int flag = 0; |
| 322 | |
| 323 | card_data = container_of(work, struct aml_card_data, work); |
| 324 | |
| 325 | if (card_data->hp_det_enable == 1) { |
| 326 | flag = jack_audio_hp_detect(card_data); |
| 327 | if (flag == -1) |
| 328 | return; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 329 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 330 | if (card_data->hp_detect_flag != flag) { |
Googler | 012a81c | 2022-09-15 14:55:24 +0800 | [diff] [blame] | 331 | card_data->hp_detect_flag = flag; |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 332 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 333 | if (card_data->hp_det_flags == OF_GPIO_ACTIVE_LOW) |
| 334 | flag = (flag) ? 0 : 1; |
| 335 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 336 | if (flag) { |
| 337 | extcon_set_state_sync(audio_extcon_headphone, |
| 338 | EXTCON_JACK_HEADPHONE, 1); |
| 339 | snd_soc_jack_report(&card_data->hp_jack.jack, |
| 340 | status, SND_JACK_HEADPHONE); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 341 | audio_send_uevent(card_data->snd_card.dev, |
| 342 | HEADPHONE_DETECTION_EVENT, 1); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 343 | } else { |
| 344 | extcon_set_state_sync(audio_extcon_headphone, |
| 345 | EXTCON_JACK_HEADPHONE, 0); |
| 346 | snd_soc_jack_report(&card_data->hp_jack.jack, 0, |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 347 | SND_JACK_HEADPHONE); |
| 348 | audio_send_uevent(card_data->snd_card.dev, |
| 349 | HEADPHONE_DETECTION_EVENT, 0); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 350 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 351 | } |
| 352 | } |
| 353 | if (card_data->mic_det_enable == 1) { |
| 354 | flag = jack_audio_micphone_detect(card_data); |
| 355 | if (flag == -1) |
| 356 | return; |
| 357 | if (card_data->mic_detect_flag != flag) { |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 358 | card_data->mic_detect_flag = flag; |
| 359 | |
| 360 | if (flag) { |
| 361 | extcon_set_state_sync(audio_extcon_microphone, |
| 362 | EXTCON_JACK_MICROPHONE, 1); |
| 363 | snd_soc_jack_report(&card_data->mic_jack.jack, |
| 364 | status, SND_JACK_MICROPHONE); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 365 | audio_send_uevent(card_data->snd_card.dev, |
| 366 | MICROPHONE_DETECTION_EVENT, 1); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 367 | } else { |
| 368 | extcon_set_state_sync(audio_extcon_microphone, |
| 369 | EXTCON_JACK_MICROPHONE, 0); |
| 370 | snd_soc_jack_report(&card_data->mic_jack.jack, |
| 371 | 0, SND_JACK_MICROPHONE); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 372 | audio_send_uevent(card_data->snd_card.dev, |
| 373 | MICROPHONE_DETECTION_EVENT, 0); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 374 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 375 | } |
| 376 | } |
| 377 | } |
| 378 | |
| 379 | static int aml_card_init_jack(struct snd_soc_card *card, |
| 380 | struct aml_jack *sjack, |
| 381 | int is_hp, char *prefix) |
| 382 | { |
| 383 | struct aml_card_data *priv = aml_card_to_priv(card); |
| 384 | struct device *dev = card->dev; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 385 | enum of_gpio_flags flags = 0; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 386 | char prop[128]; |
| 387 | char *pin_name; |
| 388 | char *gpio_name; |
| 389 | int mask; |
| 390 | int det; |
| 391 | |
| 392 | sjack->gpio.gpio = -ENOENT; |
| 393 | |
| 394 | if (is_hp) { |
| 395 | snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix); |
| 396 | pin_name = "Headphones"; |
| 397 | gpio_name = "Headphone detection"; |
| 398 | mask = SND_JACK_HEADPHONE; |
| 399 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 400 | det = of_get_named_gpio_flags(dev->of_node, prop, 0, &priv->hp_det_flags); |
| 401 | if (det < 0) { |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 402 | priv->hp_det_enable = 0; |
| 403 | return -1; |
| 404 | } |
| 405 | priv->hp_det_enable = 1; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 406 | gpio_request(det, "hp-det-gpio"); |
| 407 | } else { |
| 408 | snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix); |
| 409 | pin_name = "Mic Jack"; |
| 410 | gpio_name = "Mic detection"; |
| 411 | mask = SND_JACK_MICROPHONE; |
| 412 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 413 | det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags); |
| 414 | if (det < 0) { |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 415 | priv->mic_det_enable = 0; |
| 416 | return -1; |
| 417 | } |
| 418 | priv->mic_det_enable = 1; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 419 | gpio_request(det, "mic-det-gpio"); |
| 420 | } |
| 421 | |
| 422 | if (gpio_is_valid(det)) { |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 423 | int state; |
| 424 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 425 | sjack->pin.pin = pin_name; |
| 426 | sjack->pin.mask = mask; |
| 427 | |
| 428 | sjack->gpio.name = gpio_name; |
| 429 | sjack->gpio.report = mask; |
| 430 | sjack->gpio.gpio = det; |
| 431 | sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW); |
| 432 | sjack->gpio.debounce_time = 150; |
| 433 | |
| 434 | gpio_direction_input(det); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 435 | state = gpiod_set_pull(gpio_to_desc(det), GPIOD_PULL_DIS); |
| 436 | if (state) |
| 437 | pr_err("set gpiod pull failed, ret %d\n", state); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 438 | snd_soc_card_jack_new(card, pin_name, mask, |
| 439 | &sjack->jack, |
| 440 | &sjack->pin, 1); |
| 441 | |
| 442 | snd_soc_jack_add_gpios(&sjack->jack, 1, |
| 443 | &sjack->gpio); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 444 | } else { |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 445 | pr_info("detect gpio is invalid\n"); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 446 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 447 | |
| 448 | if (is_hp) { |
| 449 | if (det >= 0) |
| 450 | priv->hp_gpio_det = det; |
| 451 | } else { |
| 452 | if (det >= 0) |
| 453 | priv->micphone_gpio_det = det; |
| 454 | } |
| 455 | return 0; |
| 456 | } |
| 457 | |
| 458 | static void audio_jack_detect(struct aml_card_data *card_data) |
| 459 | { |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 460 | timer_setup(&card_data->timer, jack_timer_func, 0); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 461 | |
| 462 | INIT_WORK(&card_data->work, jack_work_func); |
| 463 | |
| 464 | jack_audio_start_timer(card_data, |
| 465 | msecs_to_jiffies(5000)); |
| 466 | } |
| 467 | |
| 468 | static void audio_extcon_register(struct aml_card_data *priv, |
| 469 | struct device *dev) |
| 470 | { |
| 471 | struct extcon_dev *edev; |
| 472 | int ret; |
| 473 | |
| 474 | if (priv->hp_det_enable == 1) { |
| 475 | /*audio extcon headphone*/ |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 476 | edev = devm_extcon_dev_allocate(dev, headphone_cable); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 477 | if (IS_ERR(edev)) { |
| 478 | pr_info("failed to allocate audio extcon headphone\n"); |
| 479 | return; |
| 480 | } |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 481 | /* |
| 482 | * edev->dev.parent = dev; |
| 483 | * edev->name = "audio_extcon_headphone"; |
| 484 | * dev_set_name(&edev->dev, "headphone"); |
| 485 | */ |
| 486 | ret = devm_extcon_dev_register(dev, edev); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 487 | if (ret < 0) { |
| 488 | pr_info("failed to register audio extcon headphone\n"); |
| 489 | return; |
| 490 | } |
| 491 | audio_extcon_headphone = edev; |
| 492 | } |
| 493 | if (priv->mic_det_enable == 1) { |
| 494 | /*audio extcon microphone*/ |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 495 | edev = devm_extcon_dev_allocate(dev, microphone_cable); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 496 | if (IS_ERR(edev)) { |
| 497 | pr_info("failed to allocate audio extcon microphone\n"); |
| 498 | return; |
| 499 | } |
| 500 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 501 | /* |
| 502 | * edev->dev.parent = dev; |
| 503 | * edev->name = "audio_extcon_microphone"; |
| 504 | * dev_set_name(&edev->dev, "microphone"); |
| 505 | */ |
| 506 | ret = devm_extcon_dev_register(dev, edev); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 507 | if (ret < 0) { |
| 508 | pr_info("failed to register audio extcon microphone\n"); |
| 509 | return; |
| 510 | } |
| 511 | audio_extcon_microphone = edev; |
| 512 | } |
| 513 | } |
| 514 | |
| 515 | static void aml_card_remove_jack(struct aml_jack *sjack) |
| 516 | { |
| 517 | if (gpio_is_valid(sjack->gpio.gpio)) |
| 518 | snd_soc_jack_free_gpios(&sjack->jack, 1, &sjack->gpio); |
| 519 | } |
| 520 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 521 | static int aml_card_hw_params(struct snd_pcm_substream *substream, |
| 522 | struct snd_pcm_hw_params *params) |
| 523 | { |
| 524 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 525 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
| 526 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
| 527 | struct aml_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
| 528 | struct snd_soc_dai_link *dai_link = aml_priv_to_link(priv, rtd->num); |
| 529 | struct aml_dai_props *dai_props = |
| 530 | aml_priv_to_props(priv, rtd->num); |
| 531 | unsigned int mclk = 0, mclk_fs = 0; |
| 532 | int i = 0, ret = 0; |
| 533 | int clk_idx = substream->stream; |
| 534 | |
| 535 | if (priv->mclk_fs) |
| 536 | mclk_fs = priv->mclk_fs; |
| 537 | else if (dai_props->mclk_fs) |
| 538 | mclk_fs = dai_props->mclk_fs; |
| 539 | |
| 540 | if (mclk_fs) { |
| 541 | mclk = params_rate(params) * mclk_fs; |
| 542 | |
| 543 | for (i = 0; i < rtd->num_codecs; i++) { |
| 544 | codec_dai = rtd->codec_dais[i]; |
| 545 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, |
| 546 | SND_SOC_CLOCK_IN); |
| 547 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 548 | if (ret && ret != -ENOTSUPP) { |
| 549 | pr_err("codec_dai soc dai set sysclk failed\n"); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 550 | goto err; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 551 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 552 | } |
| 553 | |
| 554 | ret = snd_soc_dai_set_sysclk(cpu_dai, clk_idx, mclk, |
| 555 | SND_SOC_CLOCK_OUT); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 556 | if (ret && ret != -ENOTSUPP) { |
| 557 | pr_err("cpu_dai soc dai set sysclk failed\n"); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 558 | goto err; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 559 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 560 | |
| 561 | ret = snd_soc_dai_set_fmt(cpu_dai, dai_link->dai_fmt); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 562 | if (ret && ret != -ENOTSUPP) { |
| 563 | pr_err("cpu_dai soc dai set fmt failed\n"); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 564 | goto err; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 565 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 566 | } |
| 567 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 568 | return 0; |
| 569 | err: |
| 570 | return ret; |
| 571 | } |
| 572 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 573 | static struct snd_soc_ops aml_card_ops = { |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 574 | .hw_params = aml_card_hw_params, |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 575 | }; |
| 576 | |
| 577 | static int aml_card_dai_init(struct snd_soc_pcm_runtime *rtd) |
| 578 | { |
| 579 | struct aml_card_data *priv = snd_soc_card_get_drvdata(rtd->card); |
| 580 | struct snd_soc_dai *codec = rtd->codec_dai; |
| 581 | struct snd_soc_dai *cpu = rtd->cpu_dai; |
| 582 | struct aml_dai_props *dai_props = |
| 583 | aml_priv_to_props(priv, rtd->num); |
| 584 | static int hp_mic_detect_cnt; |
| 585 | bool idle_clk = false; |
| 586 | int ret, i; |
| 587 | |
| 588 | /* enable dai-link mclk when CONTINUOUS clk setted */ |
| 589 | idle_clk = !!(rtd->dai_link->dai_fmt & SND_SOC_DAIFMT_CONT); |
| 590 | |
| 591 | for (i = 0; i < rtd->num_codecs; i++) { |
| 592 | codec = rtd->codec_dais[i]; |
| 593 | |
| 594 | ret = aml_card_init_dai(codec, &dai_props->codec_dai, idle_clk); |
| 595 | if (ret < 0) |
| 596 | return ret; |
| 597 | } |
| 598 | |
| 599 | ret = aml_card_init_dai(cpu, &dai_props->cpu_dai, idle_clk); |
| 600 | if (ret < 0) |
| 601 | return ret; |
| 602 | |
| 603 | if (hp_mic_detect_cnt == 0) { |
| 604 | aml_card_init_hp(rtd->card, &priv->hp_jack, PREFIX); |
| 605 | aml_card_init_mic(rtd->card, &priv->mic_jack, PREFIX); |
| 606 | hp_mic_detect_cnt = 1; |
| 607 | } |
| 608 | |
| 609 | return 0; |
| 610 | } |
| 611 | |
| 612 | static int aml_card_dai_link_of(struct device_node *node, |
| 613 | struct aml_card_data *priv, |
| 614 | int idx, |
| 615 | bool is_top_level_node) |
| 616 | { |
| 617 | struct device *dev = aml_priv_to_dev(priv); |
| 618 | struct snd_soc_dai_link *dai_link = aml_priv_to_link(priv, idx); |
| 619 | struct aml_dai_props *dai_props = aml_priv_to_props(priv, idx); |
| 620 | struct aml_dai *cpu_dai = &dai_props->cpu_dai; |
| 621 | struct aml_dai *codec_dai = &dai_props->codec_dai; |
| 622 | struct device_node *cpu = NULL; |
| 623 | struct device_node *plat = NULL; |
| 624 | struct device_node *codec = NULL; |
| 625 | char prop[128]; |
| 626 | char *prefix = ""; |
| 627 | int ret, single_cpu; |
| 628 | |
| 629 | /* For single DAI link & old style of DT node */ |
| 630 | if (is_top_level_node) |
| 631 | prefix = PREFIX; |
| 632 | |
| 633 | snprintf(prop, sizeof(prop), "%scpu", prefix); |
| 634 | cpu = of_get_child_by_name(node, prop); |
| 635 | |
| 636 | snprintf(prop, sizeof(prop), "%splat", prefix); |
| 637 | plat = of_get_child_by_name(node, prop); |
| 638 | |
| 639 | snprintf(prop, sizeof(prop), "%scodec", prefix); |
| 640 | codec = of_get_child_by_name(node, prop); |
| 641 | |
| 642 | if (!cpu || !codec) { |
| 643 | ret = -EINVAL; |
| 644 | dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); |
| 645 | goto dai_link_of_err; |
| 646 | } |
| 647 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 648 | dai_link->cpus->of_node = of_parse_phandle(cpu, DAI, 0); |
| 649 | if (!dai_link->cpus->of_node) { |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 650 | dev_err(dev, "error getting cpu phandle\n"); |
| 651 | return -EINVAL; |
| 652 | } |
| 653 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 654 | ret = aml_card_parse_daifmt(dev, node, codec, |
| 655 | prefix, &dai_link->dai_fmt); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 656 | if (ret < 0) { |
| 657 | dev_err(dev, "%s, dai fmt not found\n", |
| 658 | __func__); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 659 | goto dai_link_of_err; |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 660 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 661 | of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs); |
| 662 | |
| 663 | ret = aml_card_parse_cpu(cpu, dai_link, |
| 664 | DAI, CELL, &single_cpu); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 665 | if (ret < 0) { |
| 666 | dev_err(dev, "%s, dai-link idx:%d, error getting cpu dai name:%s\n", |
| 667 | __func__, |
| 668 | idx, |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 669 | dai_link->cpus->dai_name); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 670 | goto dai_link_of_err; |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 671 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 672 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 673 | ret = snd_soc_of_get_dai_link_codecs(dev, codec, dai_link); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 674 | |
| 675 | if (ret < 0) { |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 676 | dev_err(dev, "%s, error dai-link idx:%d, ret %d\n", __func__, idx, ret); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 677 | goto dai_link_of_err; |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 678 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 679 | |
| 680 | ret = aml_card_parse_platform(plat, dai_link, DAI, CELL); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 681 | if (ret < 0) { |
| 682 | dev_err(dev, "%s, platform not found\n", |
| 683 | __func__); |
| 684 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 685 | goto dai_link_of_err; |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 686 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 687 | |
| 688 | ret = snd_soc_of_parse_tdm_slot(cpu, &cpu_dai->tx_slot_mask, |
| 689 | &cpu_dai->rx_slot_mask, |
| 690 | &cpu_dai->slots, |
| 691 | &cpu_dai->slot_width); |
| 692 | if (ret < 0) |
| 693 | goto dai_link_of_err; |
| 694 | |
| 695 | ret = snd_soc_of_parse_tdm_slot(codec, &codec_dai->tx_slot_mask, |
| 696 | &codec_dai->rx_slot_mask, |
| 697 | &codec_dai->slots, |
| 698 | &codec_dai->slot_width); |
| 699 | if (ret < 0) |
| 700 | goto dai_link_of_err; |
| 701 | |
| 702 | ret = aml_card_parse_codec_confs(codec, &priv->snd_card); |
| 703 | if (ret < 0) |
| 704 | goto dai_link_of_err; |
| 705 | |
| 706 | ret = aml_card_parse_clk_cpu(cpu, dai_link, cpu_dai); |
| 707 | if (ret < 0) |
| 708 | goto dai_link_of_err; |
| 709 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 710 | ret = aml_card_canonicalize_dailink(dai_link); |
| 711 | if (ret < 0) |
| 712 | goto dai_link_of_err; |
| 713 | |
| 714 | /* sync with android audio hal, what's the link used for. */ |
| 715 | of_property_read_string(node, "suffix-name", &dai_props->suffix_name); |
| 716 | |
| 717 | if (dai_props->suffix_name) |
| 718 | ret = aml_card_set_dailink_name(dev, dai_link, |
| 719 | "%s-%s-%s", |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 720 | dai_link->cpus->dai_name, |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 721 | dai_link->codecs->dai_name, |
| 722 | dai_props->suffix_name); |
| 723 | else |
| 724 | ret = aml_card_set_dailink_name(dev, dai_link, |
| 725 | "%s-%s", |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 726 | dai_link->cpus->dai_name, |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 727 | dai_link->codecs->dai_name); |
| 728 | if (ret < 0) |
| 729 | goto dai_link_of_err; |
| 730 | |
| 731 | dai_link->ops = &aml_card_ops; |
| 732 | dai_link->init = aml_card_dai_init; |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 733 | dai_link->nonatomic = 1; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 734 | dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); |
| 735 | dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt); |
| 736 | dev_dbg(dev, "\tcpu : %s / %d\n", |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 737 | dai_link->cpus->dai_name, |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 738 | dai_props->cpu_dai.sysclk); |
| 739 | dev_dbg(dev, "\tcodec : %s / %d\n", |
| 740 | dai_link->codecs->dai_name, |
| 741 | dai_props->codec_dai.sysclk); |
| 742 | |
| 743 | aml_card_canonicalize_cpu(dai_link, single_cpu); |
| 744 | |
| 745 | dai_link_of_err: |
| 746 | of_node_put(cpu); |
| 747 | of_node_put(codec); |
| 748 | |
| 749 | return ret; |
| 750 | } |
| 751 | |
| 752 | static int aml_card_parse_aux_devs(struct device_node *node, |
| 753 | struct aml_card_data *priv) |
| 754 | { |
| 755 | struct device *dev = aml_priv_to_dev(priv); |
| 756 | struct device_node *aux_node; |
| 757 | int i, n, len; |
| 758 | |
| 759 | if (!of_find_property(node, PREFIX "aux-devs", &len)) |
| 760 | return 0; /* Ok to have no aux-devs */ |
| 761 | |
| 762 | n = len / sizeof(__be32); |
| 763 | if (n <= 0) |
| 764 | return -EINVAL; |
| 765 | |
| 766 | priv->snd_card.aux_dev = devm_kzalloc(dev, |
| 767 | n * sizeof(*priv->snd_card.aux_dev), GFP_KERNEL); |
| 768 | if (!priv->snd_card.aux_dev) |
| 769 | return -ENOMEM; |
| 770 | |
| 771 | for (i = 0; i < n; i++) { |
| 772 | aux_node = of_parse_phandle(node, PREFIX "aux-devs", i); |
| 773 | if (!aux_node) |
| 774 | return -EINVAL; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 775 | priv->snd_card.aux_dev[i].dlc.of_node = aux_node; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 776 | } |
| 777 | |
| 778 | priv->snd_card.num_aux_devs = n; |
| 779 | return 0; |
| 780 | } |
| 781 | |
| 782 | static int spk_mute_set(struct snd_kcontrol *kcontrol, |
| 783 | struct snd_ctl_elem_value *ucontrol) |
| 784 | { |
| 785 | struct snd_soc_card *soc_card = snd_kcontrol_chip(kcontrol); |
| 786 | struct aml_card_data *priv = aml_card_to_priv(soc_card); |
| 787 | int gpio = priv->spk_mute_gpio; |
| 788 | bool active_low = priv->spk_mute_active_low; |
| 789 | bool mute = ucontrol->value.integer.value[0]; |
| 790 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 791 | priv->spk_mute_flag = mute; |
| 792 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 793 | if (gpio_is_valid(gpio)) { |
| 794 | bool value = active_low ? !mute : mute; |
| 795 | |
| 796 | gpio_set_value(gpio, value); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 797 | pr_info("%s: mute flag = %d\n", __func__, mute); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 798 | } |
| 799 | |
| 800 | return 0; |
| 801 | } |
| 802 | |
| 803 | static int spk_mute_get(struct snd_kcontrol *kcontrol, |
| 804 | struct snd_ctl_elem_value *ucontrol) |
| 805 | { |
| 806 | struct snd_soc_card *soc_card = snd_kcontrol_chip(kcontrol); |
| 807 | struct aml_card_data *priv = aml_card_to_priv(soc_card); |
| 808 | int gpio = priv->spk_mute_gpio; |
| 809 | bool active_low = priv->spk_mute_active_low; |
| 810 | |
| 811 | if (gpio_is_valid(gpio)) { |
| 812 | bool value = gpio_get_value(gpio); |
| 813 | bool mute = active_low ? !value : value; |
| 814 | |
| 815 | ucontrol->value.integer.value[0] = mute; |
| 816 | } |
| 817 | |
| 818 | return 0; |
| 819 | } |
| 820 | |
| 821 | static const struct snd_kcontrol_new card_controls[] = { |
| 822 | SOC_SINGLE_BOOL_EXT("SPK mute", 0, |
| 823 | spk_mute_get, |
| 824 | spk_mute_set), |
| 825 | }; |
| 826 | |
| 827 | static int aml_card_parse_gpios(struct device_node *node, |
| 828 | struct aml_card_data *priv) |
| 829 | { |
| 830 | struct device *dev = aml_priv_to_dev(priv); |
| 831 | struct snd_soc_card *soc_card = &priv->snd_card; |
| 832 | enum of_gpio_flags flags; |
| 833 | int gpio; |
| 834 | bool active_low; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 835 | |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 836 | gpio = of_get_named_gpio_flags(node, "spk_mute-gpios", 0, &flags); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 837 | priv->spk_mute_gpio = gpio; |
| 838 | |
| 839 | if (gpio_is_valid(gpio)) { |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 840 | int ret; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 841 | active_low = !!(flags & OF_GPIO_ACTIVE_LOW); |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 842 | flags = active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 843 | priv->spk_mute_active_low = active_low; |
| 844 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 845 | snd_soc_add_card_controls(soc_card, card_controls, |
| 846 | ARRAY_SIZE(card_controls)); |
| 847 | |
| 848 | if (priv->spk_mute_enable) { |
| 849 | gpio_set_value(priv->spk_mute_gpio, |
| 850 | (active_low) ? GPIOF_OUT_INIT_LOW : |
| 851 | GPIOF_OUT_INIT_HIGH); |
| 852 | } else { |
| 853 | msleep(200); |
| 854 | if (!priv->spk_mute_flag) |
| 855 | gpio_set_value(priv->spk_mute_gpio, |
| 856 | (active_low) ? GPIOF_OUT_INIT_HIGH : |
| 857 | GPIOF_OUT_INIT_LOW); |
| 858 | } |
| 859 | |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 860 | ret = devm_gpio_request_one(dev, gpio, flags, "spk_mute"); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 861 | if (ret < 0) { |
| 862 | dev_err(dev, "spk_mute get gpio error!\n"); |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 863 | } |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 864 | } |
| 865 | if (IS_ERR_OR_NULL(priv->avout_mute_desc)) { |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 866 | priv->avout_mute_desc = gpiod_get(dev, |
| 867 | "avout_mute", GPIOF_OUT_INIT_LOW); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 868 | } |
| 869 | if (!IS_ERR(priv->avout_mute_desc)) { |
| 870 | if (!priv->av_mute_enable) { |
| 871 | msleep(500); |
| 872 | gpiod_direction_output(priv->avout_mute_desc, |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 873 | GPIOF_OUT_INIT_HIGH); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 874 | pr_info("av out status: %s\n", |
| 875 | gpiod_get_value(priv->avout_mute_desc) ? |
| 876 | "high" : "low"); |
| 877 | } else { |
| 878 | gpiod_direction_output(priv->avout_mute_desc, |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 879 | GPIOF_OUT_INIT_LOW); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 880 | pr_info("av out status: %s\n", |
| 881 | gpiod_get_value(priv->avout_mute_desc) ? |
| 882 | "high" : "low"); |
| 883 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 884 | } |
| 885 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 886 | return 0; |
| 887 | } |
| 888 | |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 889 | static void aml_init_work(struct work_struct *init_work) |
| 890 | { |
| 891 | struct aml_card_data *priv = NULL; |
| 892 | struct device *dev = NULL; |
| 893 | struct device_node *np = NULL; |
| 894 | |
| 895 | priv = container_of(init_work, |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 896 | struct aml_card_data, init_work); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 897 | dev = aml_priv_to_dev(priv); |
| 898 | np = dev->of_node; |
| 899 | aml_card_parse_gpios(np, priv); |
| 900 | } |
| 901 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 902 | static int aml_card_parse_of(struct device_node *node, |
| 903 | struct aml_card_data *priv) |
| 904 | { |
| 905 | struct device *dev = aml_priv_to_dev(priv); |
| 906 | struct device_node *dai_link; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 907 | int ret; |
| 908 | |
| 909 | if (!node) |
| 910 | return -EINVAL; |
| 911 | |
| 912 | dai_link = of_get_child_by_name(node, PREFIX "dai-link"); |
| 913 | |
| 914 | /* The off-codec widgets */ |
| 915 | if (of_property_read_bool(node, PREFIX "widgets")) { |
| 916 | ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, |
| 917 | PREFIX "widgets"); |
| 918 | if (ret) |
| 919 | goto card_parse_end; |
| 920 | } |
| 921 | |
| 922 | /* DAPM routes */ |
| 923 | if (of_property_read_bool(node, PREFIX "routing")) { |
| 924 | ret = snd_soc_of_parse_audio_routing(&priv->snd_card, |
| 925 | PREFIX "routing"); |
| 926 | if (ret) |
| 927 | goto card_parse_end; |
| 928 | } |
| 929 | |
| 930 | /* Factor to mclk, used in hw_params() */ |
| 931 | of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); |
| 932 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 933 | /* Single/Muti DAI link(s) & New style of DT node */ |
| 934 | if (dai_link) { |
| 935 | struct device_node *np = NULL; |
| 936 | int i = 0; |
| 937 | |
| 938 | for_each_child_of_node(node, np) { |
| 939 | dev_dbg(dev, "\tlink %d:\n", i); |
| 940 | ret = aml_card_dai_link_of(np, priv, |
| 941 | i, false); |
| 942 | if (ret < 0) { |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 943 | dev_err(dev, "parse dai_link-%d fail\n", i); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 944 | of_node_put(np); |
| 945 | goto card_parse_end; |
| 946 | } |
| 947 | i++; |
| 948 | } |
| 949 | } else { |
| 950 | /* For single DAI link & old style of DT node */ |
| 951 | ret = aml_card_dai_link_of(node, priv, 0, true); |
| 952 | if (ret < 0) |
| 953 | goto card_parse_end; |
| 954 | } |
| 955 | |
| 956 | ret = aml_card_parse_card_name(&priv->snd_card, PREFIX); |
| 957 | if (ret < 0) |
| 958 | goto card_parse_end; |
| 959 | |
| 960 | ret = aml_card_parse_aux_devs(node, priv); |
| 961 | |
| 962 | card_parse_end: |
| 963 | of_node_put(dai_link); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 964 | |
| 965 | return ret; |
| 966 | } |
| 967 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 968 | static const struct of_device_id auge_of_match[] = { |
| 969 | { |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 970 | .compatible = "amlogic, auge-sound-card", |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 971 | }, |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 972 | {} |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 973 | }; |
| 974 | MODULE_DEVICE_TABLE(of, auge_of_match); |
| 975 | |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 976 | static int card_suspend_pre(struct snd_soc_card *card) |
| 977 | { |
| 978 | struct aml_card_data *priv = snd_soc_card_get_drvdata(card); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 979 | struct device *dev = aml_priv_to_dev(priv); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 980 | |
| 981 | priv->av_mute_enable = 1; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 982 | priv->spk_mute_enable = 1; |
| 983 | aml_card_parse_gpios(dev->of_node, priv); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 984 | pr_info("it is card_pre_suspend\n"); |
| 985 | return 0; |
| 986 | } |
| 987 | |
| 988 | static int card_resume_post(struct snd_soc_card *card) |
| 989 | { |
| 990 | struct aml_card_data *priv = snd_soc_card_get_drvdata(card); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 991 | struct device *dev = aml_priv_to_dev(priv); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 992 | |
| 993 | priv->av_mute_enable = 0; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 994 | priv->spk_mute_enable = 0; |
| 995 | aml_card_parse_gpios(dev->of_node, priv); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 996 | pr_info("it is card_post_resume\n"); |
| 997 | return 0; |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 998 | |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 999 | } |
| 1000 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1001 | static irqreturn_t aml_audio_exception64_isr(int irq, void *dev_id) |
| 1002 | { |
| 1003 | unsigned int intrpt_status0, intrpt_status1; |
| 1004 | |
| 1005 | intrpt_status0 = audiobus_read(EE_AUDIO_EXCEPTION_IRQ_STS0); |
| 1006 | intrpt_status1 = audiobus_read(EE_AUDIO_EXCEPTION_IRQ_STS1); |
| 1007 | |
| 1008 | /* clear irq bits immediametely */ |
| 1009 | audiobus_write(EE_AUDIO_EXCEPTION_IRQ_CLR0, intrpt_status0); |
| 1010 | audiobus_write(EE_AUDIO_EXCEPTION_IRQ_CLR1, intrpt_status1); |
| 1011 | |
| 1012 | pr_debug("0 - 31 exception status is 0x%x\n", intrpt_status0); |
| 1013 | pr_debug("32 - 63 exception status is 0x%x\n", intrpt_status1); |
| 1014 | |
| 1015 | /* TODO handle exception */ |
| 1016 | |
| 1017 | return IRQ_HANDLED; |
| 1018 | } |
| 1019 | |
| 1020 | static int register_audio_exception64_isr(int irq_exception64) |
| 1021 | { |
| 1022 | int ret = 0; |
| 1023 | |
| 1024 | /* open irq mask, default is close |
| 1025 | * audiobus_write(EE_AUDIO_EXCEPTION_IRQ_MASK0, 0xfffdff3f); |
| 1026 | * audiobus_write(EE_AUDIO_EXCEPTION_IRQ_MASK1, 0xffc3777f); |
| 1027 | |
| 1028 | * set threshold value |
| 1029 | * audiobus_write(EE_AUDIO_ARB_CTRL1, 0xffff); |
| 1030 | * audiobus_write(EE_AUDIO_SPDIFIN_CTRL7, 0xffff); |
| 1031 | */ |
| 1032 | |
| 1033 | ret = request_irq(irq_exception64, |
| 1034 | aml_audio_exception64_isr, |
| 1035 | 0, |
| 1036 | "audio_exception64", |
| 1037 | NULL); |
| 1038 | |
| 1039 | if (ret) |
| 1040 | pr_err("failed claim irq_exception64 %u, ret: %d\n", irq_exception64, ret); |
| 1041 | |
| 1042 | return ret; |
| 1043 | } |
| 1044 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1045 | static int aml_card_probe(struct platform_device *pdev) |
| 1046 | { |
| 1047 | struct aml_card_data *priv; |
| 1048 | struct snd_soc_dai_link *dai_link; |
| 1049 | struct aml_dai_props *dai_props; |
| 1050 | struct device_node *np = pdev->dev.of_node; |
| 1051 | struct device *dev = &pdev->dev; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1052 | int num, ret, i; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1053 | |
| 1054 | /* Get the number of DAI links */ |
| 1055 | if (np && of_get_child_by_name(np, PREFIX "dai-link")) |
| 1056 | num = of_get_child_count(np); |
| 1057 | else |
| 1058 | num = 1; |
| 1059 | |
| 1060 | /* Allocate the private data and the DAI link array */ |
| 1061 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
| 1062 | if (!priv) |
| 1063 | return -ENOMEM; |
| 1064 | |
| 1065 | dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); |
| 1066 | dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL); |
| 1067 | if (!dai_props || !dai_link) |
| 1068 | return -ENOMEM; |
| 1069 | |
| 1070 | priv->dai_props = dai_props; |
| 1071 | priv->dai_link = dai_link; |
| 1072 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1073 | for (i = 0; i < num; i++) { |
| 1074 | dai_link[i].cpus = &dai_props[i].cpus; |
| 1075 | dai_link[i].num_cpus = 1; |
| 1076 | dai_link[i].codecs = &dai_props[i].codecs; |
| 1077 | dai_link[i].num_codecs = 1; |
| 1078 | dai_link[i].platforms = &dai_props[i].platforms; |
| 1079 | dai_link[i].num_platforms = 1; |
| 1080 | } |
| 1081 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1082 | /* Init snd_soc_card */ |
| 1083 | priv->snd_card.owner = THIS_MODULE; |
| 1084 | priv->snd_card.dev = dev; |
| 1085 | priv->snd_card.dai_link = priv->dai_link; |
| 1086 | priv->snd_card.num_links = num; |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 1087 | priv->snd_card.suspend_pre = card_suspend_pre; |
| 1088 | priv->snd_card.resume_post = card_resume_post; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1089 | |
| 1090 | if (np && of_device_is_available(np)) { |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1091 | ret = aml_card_parse_of(np, priv); |
| 1092 | if (ret < 0) { |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 1093 | dev_err(dev, "%s, aml_card_parse_of error %d %s\n", |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 1094 | __func__, |
| 1095 | ret, |
| 1096 | (ret == -EPROBE_DEFER) ? "PROBE RETRY" : ""); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1097 | goto err; |
| 1098 | } |
| 1099 | |
| 1100 | } else { |
| 1101 | struct aml_card_info *cinfo; |
| 1102 | |
| 1103 | cinfo = dev->platform_data; |
| 1104 | if (!cinfo) { |
| 1105 | dev_err(dev, "no info for asoc-aml-card\n"); |
| 1106 | return -EINVAL; |
| 1107 | } |
| 1108 | |
| 1109 | if (!cinfo->name || |
| 1110 | !cinfo->codec_dai.name || |
| 1111 | !cinfo->codec || |
| 1112 | !cinfo->platform || |
| 1113 | !cinfo->cpu_dai.name) { |
| 1114 | dev_err(dev, "insufficient aml_card_info settings\n"); |
| 1115 | return -EINVAL; |
| 1116 | } |
| 1117 | |
| 1118 | priv->snd_card.name = |
| 1119 | (cinfo->card) ? cinfo->card : cinfo->name; |
| 1120 | dai_link->name = cinfo->name; |
| 1121 | dai_link->stream_name = cinfo->name; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1122 | dai_link->platforms->name = cinfo->platform; |
| 1123 | dai_link->codecs->name = cinfo->codec; |
| 1124 | dai_link->cpus->dai_name = cinfo->cpu_dai.name; |
| 1125 | dai_link->codecs->dai_name = cinfo->codec_dai.name; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1126 | dai_link->dai_fmt = cinfo->daifmt; |
| 1127 | dai_link->init = aml_card_dai_init; |
| 1128 | memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, |
| 1129 | sizeof(priv->dai_props->cpu_dai)); |
| 1130 | memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, |
| 1131 | sizeof(priv->dai_props->codec_dai)); |
| 1132 | } |
| 1133 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1134 | priv->irq_exception64 = |
| 1135 | platform_get_irq_byname(pdev, "audio_exception64"); |
| 1136 | if (priv->irq_exception64 > 0) |
| 1137 | register_audio_exception64_isr(priv->irq_exception64); |
| 1138 | |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 1139 | platform_set_drvdata(pdev, priv); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1140 | snd_soc_card_set_drvdata(&priv->snd_card, priv); |
| 1141 | |
| 1142 | ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); |
| 1143 | if (ret < 0) { |
| 1144 | dev_err(dev, "failed to register sound card\n"); |
| 1145 | goto err; |
| 1146 | } |
| 1147 | |
| 1148 | /* Add controls */ |
| 1149 | ret = aml_card_add_controls(&priv->snd_card); |
| 1150 | if (ret < 0) { |
| 1151 | dev_err(dev, "failed to register mixer kcontrols\n"); |
| 1152 | goto err; |
| 1153 | } |
| 1154 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1155 | card_add_effects_init(&priv->snd_card); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1156 | |
| 1157 | if (priv->hp_det_enable == 1 || priv->mic_det_enable == 1) { |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1158 | priv->hp_detect_flag = -1; |
| 1159 | priv->hp_last_state = -1; |
| 1160 | priv->mic_detect_flag = -1; |
| 1161 | priv->micphone_last_state = -1; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1162 | audio_jack_detect(priv); |
| 1163 | audio_extcon_register(priv, dev); |
| 1164 | } |
Googler | 9726be6 | 2022-12-14 05:53:31 +0000 | [diff] [blame] | 1165 | |
| 1166 | snd_soc_add_card_controls(&priv->snd_card, snd_user_controls, |
| 1167 | ARRAY_SIZE(snd_user_controls)); |
| 1168 | |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 1169 | priv->av_mute_enable = 0; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1170 | priv->spk_mute_enable = 0; |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 1171 | INIT_WORK(&priv->init_work, aml_init_work); |
| 1172 | schedule_work(&priv->init_work); |
| 1173 | |
| 1174 | return 0; |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1175 | err: |
| 1176 | pr_err("%s error ret:%d\n", __func__, ret); |
| 1177 | aml_card_clean_reference(&priv->snd_card); |
| 1178 | |
| 1179 | return ret; |
| 1180 | } |
| 1181 | |
| 1182 | static int aml_card_remove(struct platform_device *pdev) |
| 1183 | { |
| 1184 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
| 1185 | struct aml_card_data *priv = snd_soc_card_get_drvdata(card); |
| 1186 | |
| 1187 | aml_card_remove_jack(&priv->hp_jack); |
| 1188 | aml_card_remove_jack(&priv->mic_jack); |
| 1189 | jack_audio_stop_timer(priv); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1190 | |
| 1191 | if (priv->irq_exception64 > 0) |
| 1192 | free_irq(priv->irq_exception64, NULL); |
| 1193 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1194 | return aml_card_clean_reference(card); |
| 1195 | } |
| 1196 | |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 1197 | static void aml_card_platform_shutdown(struct platform_device *pdev) |
| 1198 | { |
| 1199 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
| 1200 | struct aml_card_data *priv = snd_soc_card_get_drvdata(card); |
| 1201 | |
| 1202 | priv->av_mute_enable = 1; |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1203 | priv->spk_mute_enable = 1; |
| 1204 | aml_card_parse_gpios(pdev->dev.of_node, priv); |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 1205 | } |
| 1206 | |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1207 | static struct platform_driver aml_card = { |
| 1208 | .driver = { |
| 1209 | .name = "asoc-aml-card", |
| 1210 | .pm = &snd_soc_pm_ops, |
| 1211 | .of_match_table = auge_of_match, |
| 1212 | }, |
| 1213 | .probe = aml_card_probe, |
| 1214 | .remove = aml_card_remove, |
Googler | 38bda47 | 2022-08-19 10:07:08 -0700 | [diff] [blame] | 1215 | .shutdown = aml_card_platform_shutdown, |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1216 | }; |
| 1217 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1218 | int __init aml_card_init(void) |
| 1219 | { |
| 1220 | return platform_driver_register(&aml_card); |
| 1221 | } |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1222 | |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1223 | void __exit aml_card_exit(void) |
| 1224 | { |
| 1225 | platform_driver_unregister(&aml_card); |
| 1226 | } |
| 1227 | |
| 1228 | #ifndef MODULE |
| 1229 | module_init(aml_card_init); |
| 1230 | module_exit(aml_card_exit); |
Googler | 4f18c0c | 2022-09-20 17:23:36 +0800 | [diff] [blame] | 1231 | MODULE_ALIAS("platform:asoc-aml-card"); |
| 1232 | MODULE_LICENSE("GPL v2"); |
| 1233 | MODULE_DESCRIPTION("ASoC aml Sound Card"); |
| 1234 | MODULE_AUTHOR("AMLogic, Inc."); |
Googler | 9398cc3 | 2022-12-02 17:21:52 +0800 | [diff] [blame^] | 1235 | #endif |