summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Langlais <philippe.langlais@stericsson.com>2011-10-20 10:33:31 +0200
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:04:41 +0200
commit9d5ac7304583952239cf71a3b3a58f7d3cc742b3 (patch)
treefb2494fe0d73d0aca367868be6762890dbce5227
parent76e10d158efb6d4516018846f60c2ab5501900bc (diff)
misc: Add audio_io_dev driver
Signed-off-by: Robert Marklund <robert.marklund@stericsson.com>
-rw-r--r--arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h224
-rw-r--r--arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h37
-rw-r--r--drivers/misc/audio_io_dev/Kconfig11
-rw-r--r--drivers/misc/audio_io_dev/Makefile9
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_ab8500_reg_defs.h349
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_core.c1464
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_core.h133
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_dev.c738
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_dev.h32
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_func.c4371
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_func.h359
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.c189
-rw-r--r--drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.h50
13 files changed, 7966 insertions, 0 deletions
diff --git a/arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h b/arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h
new file mode 100644
index 00000000000..73dc9d9ee7e
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ste_audio_io_ioctl.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#ifndef _AUDIOIO_IOCTL_H_
+#define _AUDIOIO_IOCTL_H_
+
+
+#define AUDIOIO_IOC_MAGIC 'N'
+#define AUDIOIO_READ_REGISTER _IOWR(AUDIOIO_IOC_MAGIC, 1,\
+ struct audioio_data_t)
+#define AUDIOIO_WRITE_REGISTER _IOW(AUDIOIO_IOC_MAGIC, 2,\
+ struct audioio_data_t)
+#define AUDIOIO_PWR_CTRL_TRNSDR _IOW(AUDIOIO_IOC_MAGIC, 3,\
+ struct audioio_pwr_ctrl_t)
+#define AUDIOIO_PWR_STS_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 4,\
+ struct audioio_pwr_ctrl_t)
+#define AUDIOIO_LOOP_CTRL _IOW(AUDIOIO_IOC_MAGIC, 5,\
+ struct audioio_loop_ctrl_t)
+#define AUDIOIO_LOOP_STS _IOR(AUDIOIO_IOC_MAGIC, 6,\
+ struct audioio_loop_ctrl_t)
+#define AUDIOIO_GET_TRNSDR_GAIN_CAPABILITY _IOR(AUDIOIO_IOC_MAGIC, 7,\
+ struct audioio_get_gain_t)
+#define AUDIOIO_GAIN_CAP_LOOP _IOR(AUDIOIO_IOC_MAGIC, 8,\
+ struct audioio_gain_loop_t)
+#define AUDIOIO_SUPPORT_LOOP _IOR(AUDIOIO_IOC_MAGIC, 9,\
+ struct audioio_support_loop_t)
+#define AUDIOIO_GAIN_DESC_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 10,\
+ struct audioio_gain_desc_trnsdr_t)
+#define AUDIOIO_GAIN_CTRL_TRNSDR _IOW(AUDIOIO_IOC_MAGIC, 11,\
+ struct audioio_gain_ctrl_trnsdr_t)
+#define AUDIOIO_GAIN_QUERY_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 12,\
+ struct audioio_gain_ctrl_trnsdr_t)
+#define AUDIOIO_MUTE_CTRL_TRNSDR _IOW(AUDIOIO_IOC_MAGIC, 13,\
+ struct audioio_mute_trnsdr_t)
+#define AUDIOIO_MUTE_STS_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 14,\
+ struct audioio_mute_trnsdr_t)
+#define AUDIOIO_FADE_CTRL _IOW(AUDIOIO_IOC_MAGIC, 15,\
+ struct audioio_fade_ctrl_t)
+#define AUDIOIO_BURST_CTRL _IOW(AUDIOIO_IOC_MAGIC, 16,\
+ struct audioio_burst_ctrl_t)
+#define AUDIOIO_READ_ALL_ACODEC_REGS_CTRL _IOW(AUDIOIO_IOC_MAGIC, 17,\
+ struct audioio_read_all_acodec_reg_ctrl_t)
+#define AUDIOIO_FSBITCLK_CTRL _IOW(AUDIOIO_IOC_MAGIC, 18,\
+ struct audioio_fsbitclk_ctrl_t)
+#define AUDIOIO_PSEUDOBURST_CTRL _IOW(AUDIOIO_IOC_MAGIC, 19,\
+ struct audioio_pseudoburst_ctrl_t)
+#define AUDIOIO_AUDIOCODEC_PWR_CTRL _IOW(AUDIOIO_IOC_MAGIC, 20, \
+ struct audioio_acodec_pwr_ctrl_t)
+#define AUDIOIO_FIR_COEFFS_CTRL _IOW(AUDIOIO_IOC_MAGIC, 21, \
+ struct audioio_fir_coefficients_t)
+#define AUDIOIO_LOOP_GAIN_DESC_TRNSDR _IOR(AUDIOIO_IOC_MAGIC, 22,\
+ struct audioio_gain_desc_trnsdr_t)
+/* audio codec channel ids */
+#define EAR_CH 0
+#define HS_CH 1
+#define IHF_CH 2
+#define VIBL_CH 3
+#define VIBR_CH 4
+#define MIC1A_CH 5
+#define MIC1B_CH 6
+#define MIC2_CH 7
+#define LIN_CH 8
+#define DMIC12_CH 9
+#define DMIC34_CH 10
+#define DMIC56_CH 11
+#define MULTI_MIC_CH 12
+#define FMRX_CH 13
+#define FMTX_CH 14
+#define BLUETOOTH_CH 15
+
+#define FIRST_CH EAR_CH
+#define LAST_CH BLUETOOTH_CH
+
+#define MAX_NO_TRANSDUCERS 16
+#define STE_AUDIOIO_MAX_COEFFICIENTS 128
+#define MAX_NO_OF_LOOPS 19
+
+#define AUDIOIO_TRUE 1
+#define AUDIOIO_FALSE 0
+
+enum AUDIOIO_COMMON_SWITCH {
+ AUDIOIO_COMMON_OFF = 0,
+ AUDIOIO_COMMON_ON,
+ AUDIOIO_COMMON_ALLCHANNEL_UNSUPPORTED = 0xFFFF
+};
+
+enum AUDIOIO_HAL_HW_LOOPS {
+ AUDIOIO_NO_LOOP = 0x0,
+ AUDIOIO_SIDETONE_LOOP = 0x01,
+ AUDIOIO_MIC1B_TO_HFL = 0x02,
+ AUDIOIO_MIC1B_TO_HFR = 0x04,
+ AUDIOIO_MIC1B_TO_EAR = 0x08,
+ AUDIOIO_MIC1A_TO_HSL = 0x10,
+ AUDIOIO_MIC1A_TO_HSR = 0x20,
+ AUDIOIO_MIC1A_TO_HSR_HSL = 0x40,
+ AUDIOIO_LINEIN_TO_HF = 0x80,
+ AUDIOIO_DMIC12_TO_HSR_HSL = 0x100,
+ AUDIOIO_DIC34_TO_HSR_HSL = 0x200,
+ AUDIOIO_DIC56_TO_HSR_HSL = 0x400,
+ AUDIOIO_DMIC12_TO_ST = 0x800,
+ AUDIOIO_DMIC34_TO_ST = 0x1000,
+ AUDIOIO_DMIC56_TO_ST = 0x2000,
+ AUDIOIO_ANC_LOOP = 0x4000,
+ AUDIOIO_LININ_HS = 0x8000,
+ AUDIOIO_LININL_HSL = 0x10000,
+ AUDIOIO_LININ_HSR = 0x20000
+};
+
+
+enum AUDIOIO_FADE_PERIOD {
+ e_FADE_00,
+ e_FADE_01,
+ e_FADE_10,
+ e_FADE_11
+};
+
+enum AUDIOIO_CH_INDEX {
+ e_CHANNEL_1 = 0x01,
+ e_CHANNEL_2 = 0x02,
+ e_CHANNEL_3 = 0x04,
+ e_CHANNEL_4 = 0x08,
+ e_CHANNEL_ALL = 0x0f
+};
+
+struct audioio_data_t {
+ unsigned char block;
+ unsigned char addr;
+ unsigned char data;
+};
+
+struct audioio_pwr_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+ int channel_type;
+ enum AUDIOIO_CH_INDEX channel_index;
+};
+
+struct audioio_acodec_pwr_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+};
+
+struct audioio_loop_ctrl_t {
+ enum AUDIOIO_HAL_HW_LOOPS hw_loop;
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+ int channel_type;
+ enum AUDIOIO_CH_INDEX channel_index;
+ int loop_gain;
+};
+
+struct audioio_get_gain_t {
+ unsigned int num_channels;
+ unsigned short max_num_gain;
+};
+
+struct audioio_gain_loop_t {
+ int channel_type;
+ unsigned short num_loop;
+ unsigned short max_gains;
+};
+
+struct audioio_support_loop_t {
+ int channel_type;
+ unsigned short spprtd_loop_index;
+};
+
+struct audioio_gain_desc_trnsdr_t {
+ enum AUDIOIO_CH_INDEX channel_index;
+ int channel_type;
+ unsigned short gain_index;
+ int min_gain;
+ int max_gain;
+ unsigned int gain_step;
+};
+
+struct audioio_gain_ctrl_trnsdr_t {
+ enum AUDIOIO_CH_INDEX channel_index;
+ int channel_type;
+ unsigned short gain_index;
+ int gain_value;
+ unsigned int linear;
+};
+
+struct audioio_mute_trnsdr_t {
+ int channel_type;
+ enum AUDIOIO_CH_INDEX channel_index;
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+};
+
+struct audioio_fade_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+ enum AUDIOIO_FADE_PERIOD fade_period;
+ int channel_type;
+ enum AUDIOIO_CH_INDEX channel_index;
+};
+
+struct audioio_burst_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+ int channel_type;
+ int burst_fifo_interrupt_sample_count;
+ int burst_fifo_length;/* BFIFOTx */
+ int burst_fifo_switch_frame;
+ int burst_fifo_sample_number;
+};
+
+struct audioio_read_all_acodec_reg_ctrl_t {
+ unsigned char data[200];
+};
+
+struct audioio_fsbitclk_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+};
+
+struct audioio_pseudoburst_ctrl_t {
+ enum AUDIOIO_COMMON_SWITCH ctrl_switch;
+};
+
+struct audioio_fir_coefficients_t {
+ unsigned char start_addr;
+ unsigned short coefficients[STE_AUDIOIO_MAX_COEFFICIENTS];
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h b/arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h
new file mode 100644
index 00000000000..6b6a558e90a
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/ste_audio_io_vibrator.h
@@ -0,0 +1,37 @@
+/*
+* Overview:
+* Header File defining vibrator kernel space interface
+*
+* Copyright (C) 2010 ST Ericsson
+*
+* 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 _STE_AUDIO_IO_VIBRATOR_H_
+#define _STE_AUDIO_IO_VIBRATOR_H_
+
+/* Client definitions which can use vibrator, defined as bitmask */
+#define STE_AUDIOIO_CLIENT_AUDIO_L 1
+#define STE_AUDIOIO_CLIENT_AUDIO_R 2
+#define STE_AUDIOIO_CLIENT_FF_VIBRA 4
+#define STE_AUDIOIO_CLIENT_TIMED_VIBRA 8
+
+/*
+ * Define vibrator's maximum speed allowed
+ * Duty cycle supported by vibrator's PWM is 0-100
+ */
+#define STE_AUDIOIO_VIBRATOR_MAX_SPEED 100
+
+/* Vibrator speed structure */
+struct ste_vibra_speed {
+ unsigned char positive;
+ unsigned char negative;
+};
+
+/* Vibrator control function - uses PWM source */
+int ste_audioio_vibrator_pwm_control(int client,
+ struct ste_vibra_speed left_speed, struct ste_vibra_speed right_speed);
+
+#endif
diff --git a/drivers/misc/audio_io_dev/Kconfig b/drivers/misc/audio_io_dev/Kconfig
new file mode 100644
index 00000000000..57bb77172f7
--- /dev/null
+++ b/drivers/misc/audio_io_dev/Kconfig
@@ -0,0 +1,11 @@
+#
+# AB8500 Audio IO Device Driver configuration
+#
+config STE_AUDIO_IO_DEV
+ bool "AB8500 Audio IO device driver"
+ depends on ARCH_U8500 && AB8500_CORE && STM_MSP_I2S
+ default y
+ ---help---
+ If you say Y here, you will enable the AB8500 Audio IO device driver.
+
+ If unsure, say N.
diff --git a/drivers/misc/audio_io_dev/Makefile b/drivers/misc/audio_io_dev/Makefile
new file mode 100644
index 00000000000..44b21fcc573
--- /dev/null
+++ b/drivers/misc/audio_io_dev/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for AB8500 device drivers
+#
+obj-$(CONFIG_STE_AUDIO_IO_DEV) += ste_audio_io.o
+ste_audio_io-objs := ste_audio_io_dev.o\
+ ste_audio_io_core.o\
+ ste_audio_io_func.o\
+ ste_audio_io_hwctrl_common.o
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_ab8500_reg_defs.h b/drivers/misc/audio_io_dev/ste_audio_io_ab8500_reg_defs.h
new file mode 100644
index 00000000000..1436430f7de
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_ab8500_reg_defs.h
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+
+#ifndef _AUDIOIO_REG_DEFS_H_
+#define _AUDIOIO_REG_DEFS_H_
+
+
+ /* Registers */
+#define POWER_UP_CONTROL_REG 0x0D00
+#define SOFTWARE_RESET_REG 0x0D01
+#define DIGITAL_AD_CHANNELS_ENABLE_REG 0x0D02
+#define DIGITAL_DA_CHANNELS_ENABLE_REG 0x0D03
+#define LOW_POWER_HS_EAR_CONF_REG 0x0D04
+#define LINE_IN_MIC_CONF_REG 0x0D05
+#define DMIC_ENABLE_REG 0x0D06
+#define ADC_DAC_ENABLE_REG 0x0D07
+#define ANALOG_OUTPUT_ENABLE_REG 0x0D08
+#define DIGITAL_OUTPUT_ENABLE_REG 0x0D09
+#define MUTE_HS_EAR_REG 0x0D0A
+#define SHORT_CIRCUIT_DISABLE_REG 0x0D0B
+#define NCP_ENABLE_HS_AUTOSTART_REG 0x0D0C
+#define ENVELOPE_THRESHOLD_REG 0x0D0D
+#define ENVELOPE_DECAY_TIME_REG 0x0D0E
+#define VIB_DRIVER_CONF_REG 0x0D0F
+#define PWM_VIBNL_CONF_REG 0x0D10
+#define PWM_VIBPL_CONF_REG 0x0D11
+#define PWM_VIBNR_CONF_REG 0x0D12
+#define PWM_VIBPR_CONF_REG 0x0D13
+#define ANALOG_MIC1_GAIN_REG 0x0D14
+#define ANALOG_MIC2_GAIN_REG 0x0D15
+#define ANALOG_HS_GAIN_REG 0x0D16
+#define ANALOG_LINE_IN_GAIN_REG 0x0D17
+#define LINE_IN_TO_HSL_GAIN_REG 0x0D18
+#define LINE_IN_TO_HSR_GAIN_REG 0x0D19
+#define AD_FILTER_CONF_REG 0x0D1A
+#define IF0_IF1_MASTER_CONF_REG 0x0D1B
+#define IF0_CONF_REG 0x0D1C
+#define TDM_IF_BYPASS_B_FIFO_REG 0x0D1D
+#define IF1_CONF_REG 0x0D1E
+#define AD_ALLOCATION_TO_SLOT0_1_REG 0x0D1F
+#define AD_ALLOCATION_TO_SLOT2_3_REG 0x0D20
+#define AD_ALLOCATION_TO_SLOT4_5_REG 0x0D21
+#define AD_ALLOCATION_TO_SLOT6_7_REG 0x0D22
+#define AD_ALLOCATION_TO_SLOT8_9_REG 0x0D23
+#define AD_ALLOCATION_TO_SLOT10_11_REG 0x0D24
+#define AD_ALLOCATION_TO_SLOT12_13_REG 0x0D25
+#define AD_ALLOCATION_TO_SLOT14_15_REG 0x0D26
+#define AD_ALLOCATION_TO_SLOT16_17_REG 0x0D27
+#define AD_ALLOCATION_TO_SLOT18_19_REG 0x0D28
+#define AD_ALLOCATION_TO_SLOT20_21_REG 0x0D29
+#define AD_ALLOCATION_TO_SLOT22_23_REG 0x0D2A
+#define AD_ALLOCATION_TO_SLOT24_25_REG 0x0D2B
+#define AD_ALLOCATION_TO_SLOT26_27_REG 0x0D2C
+#define AD_ALLOCATION_TO_SLOT28_29_REG 0x0D2D
+#define AD_ALLOCATION_TO_SLOT30_31_REG 0x0D2E
+#define AD_SLOT_0_TO_7_TRISTATE_REG 0x0D2F
+#define AD_SLOT_8_TO_15_TRISTATE_REG 0x0D30
+#define AD_SLOT_16_TO_23_TRISTATE_REG 0x0D31
+#define AD_SLOT_24_TO_31_TRISTATE_REG 0x0D32
+#define SLOT_SELECTION_TO_DA1_REG 0x0D33
+#define SLOT_SELECTION_TO_DA2_REG 0x0D34
+#define SLOT_SELECTION_TO_DA3_REG 0x0D35
+#define SLOT_SELECTION_TO_DA4_REG 0x0D36
+#define SLOT_SELECTION_TO_DA5_REG 0x0D37
+#define SLOT_SELECTION_TO_DA6_REG 0x0D38
+#define SLOT_SELECTION_TO_DA7_REG 0x0D39
+#define SLOT_SELECTION_TO_DA8_REG 0x0D3A
+#define CLASS_D_EMI_PARALLEL_CONF_REG 0x0D3B
+#define CLASS_D_PATH_CONTROL_REG 0x0D3C
+#define CLASS_D_DITHER_CONTROL_REG 0x0D3D
+#define DMIC_DECIMATOR_FILTER_REG 0x0D3E
+#define DIGITAL_MUXES_REG1 0x0D3F
+#define DIGITAL_MUXES_REG2 0x0D40
+#define AD1_DIGITAL_GAIN_REG 0x0D41
+#define AD2_DIGITAL_GAIN_REG 0x0D42
+#define AD3_DIGITAL_GAIN_REG 0x0D43
+#define AD4_DIGITAL_GAIN_REG 0x0D44
+#define AD5_DIGITAL_GAIN_REG 0x0D45
+#define AD6_DIGITAL_GAIN_REG 0x0D46
+#define DA1_DIGITAL_GAIN_REG 0x0D47
+#define DA2_DIGITAL_GAIN_REG 0x0D48
+#define DA3_DIGITAL_GAIN_REG 0x0D49
+#define DA4_DIGITAL_GAIN_REG 0x0D4A
+#define DA5_DIGITAL_GAIN_REG 0x0D4B
+#define DA6_DIGITAL_GAIN_REG 0x0D4C
+#define AD1_TO_HFL_DIGITAL_GAIN_REG 0x0D4D
+#define AD2_TO_HFR_DIGITAL_GAIN_REG 0x0D4E
+#define HSL_EAR_DIGITAL_GAIN_REG 0x0D4F
+#define HSR_DIGITAL_GAIN_REG 0x0D50
+#define SIDETONE_FIR1_GAIN_REG 0x0D51
+#define SIDETONE_FIR2_GAIN_REG 0x0D52
+#define ANC_FILTER_CONTROL_REG 0x0D53
+#define ANC_WARPED_GAIN_REG 0x0D54
+#define ANC_FIR_OUTPUT_GAIN_REG 0x0D55
+#define ANC_IIR_OUTPUT_GAIN_REG 0x0D56
+#define ANC_FIR_COEFF_MSB_REG 0x0D57
+#define ANC_FIR_COEFF_LSB_REG 0x0D58
+#define ANC_IIR_COEFF_MSB_REG 0x0D59
+#define ANC_IIR_COEFF_LSB_REG 0x0D5A
+#define ANC_WARP_DELAY_MSB_REG 0x0D5B
+#define ANC_WARP_DELAY_LSB_REG 0x0D5C
+#define ANC_FIR_PEAK_MSB_REG 0x0D5D
+#define ANC_FIR_PEAK_LSB_REG 0x0D5E
+#define ANC_IIR_PEAK_MSB_REG 0x0D5F
+#define ANC_IIR_PEAK_LSB_REG 0x0D60
+#define SIDETONE_FIR_ADDR_REG 0x0D61
+#define SIDETONE_FIR_COEFF_MSB_REG 0x0D62
+#define SIDETONE_FIR_COEFF_LSB_REG 0x0D63
+#define FILTERS_CONTROL_REG 0x0D64
+#define IRQ_MASK_LSB_REG 0x0D65
+#define IRQ_STATUS_LSB_REG 0x0D66
+#define IRQ_MASK_MSB_REG 0x0D67
+#define IRQ_STATUS_MSB_REG 0x0D68
+#define BURST_FIFO_INT_CONTROL_REG 0x0D69
+#define BURST_FIFO_LENGTH_REG 0x0D6A
+#define BURST_FIFO_CONTROL_REG 0x0D6B
+#define BURST_FIFO_SWITCH_FRAME_REG 0x0D6C
+#define BURST_FIFO_WAKE_UP_DELAY_REG 0x0D6D
+#define BURST_FIFO_SAMPLES_REG 0x0D6E
+#define REVISION_REG 0x0D6F
+
+/* POWER_UP_CONTROL_REG Masks */
+#define DEVICE_POWER_UP 0x80
+#define ANALOG_PARTS_POWER_UP 0x08
+
+/* SOFTWARE_RESET_REG Masks */
+#define SW_RESET 0x80
+
+/* DIGITAL_AD_CHANNELS_ENABLE_REG Masks */
+#define EN_AD1 0x80
+#define EN_AD2 0x80
+#define EN_AD3 0x20
+#define EN_AD4 0x20
+#define EN_AD5 0x08
+#define EN_AD6 0x04
+
+/* DIGITAL_DA_CHANNELS_ENABLE_REG Masks */
+#define EN_DA1 0x80
+#define EN_DA2 0x40
+#define EN_DA3 0x20
+#define EN_DA4 0x10
+#define EN_DA5 0x08
+#define EN_DA6 0x04
+
+/* LOW_POWER_HS_EAR_CONF_REG Masks */
+#define LOW_POWER_HS 0x80
+#define HS_DAC_DRIVER_LP 0x40
+#define HS_DAC_LP 0x20
+#define EAR_DAC_LP 0x10
+
+/* LINE_IN_MIC_CONF_REG Masks */
+#define EN_MIC1 0x80
+#define EN_MIC2 0x40
+#define EN_LIN_IN_L 0x20
+#define EN_LIN_IN_R 0x10
+#define MUT_MIC1 0x08
+#define MUT_MIC2 0x04
+#define MUT_LIN_IN_L 0x02
+#define MUT_LIN_IN_R 0x01
+
+/* DMIC_ENABLE_REG Masks */
+#define EN_DMIC1 0x80
+#define EN_DMIC2 0x40
+#define EN_DMIC3 0x20
+#define EN_DMIC4 0x10
+#define EN_DMIC5 0x08
+#define EN_DMIC6 0x04
+
+/* ADC_DAC_ENABLE_REG Masks */
+#define SEL_MIC1B_CLR_MIC1A 0x80
+#define SEL_LINR_CLR_MIC2 0x40
+#define POWER_UP_HSL_DAC 0x20
+#define POWER_UP_HSR_DAC 0x10
+#define POWER_UP_ADC1 0x04
+#define POWER_UP_ADC3 0x02
+#define POWER_UP_ADC2 0x01
+
+/* ANALOG_OUTPUT_ENABLE_REG and DIGITAL_OUTPUT_ENABLE_REG and
+ MUTE_HS_EAR_REG Masks */
+#define EN_EAR_DAC_MASK 0x04
+#define EN_HSL_DAC_MASK 0x02
+#define EN_HSR_DAC_MASK 0x01
+#define EN_EAR_MASK 0x40
+#define EN_HSL_MASK 0x20
+#define EN_HSR_MASK 0x10
+#define EN_HFL_MASK 0x08
+#define EN_HFR_MASK 0x04
+#define EN_VIBL_MASK 0x02
+#define EN_VIBR_MASK 0x01
+
+/* SHORT_CIRCUIT_DISABLE_REG Masks */
+#define HS_SHORT_DIS 0x20
+#define HS_PULL_DOWN_EN 0x10
+#define HS_OSC_EN 0x04
+#define DIS_HS_FAD 0x02
+#define HS_ZCD_DIS 0x01
+
+/* NCP_ENABLE_HS_AUTOSTART_REG Masks */
+#define EN_NEG_CP 0x80
+#define HS_AUTO_EN 0x01
+
+/* ANALOG_MIC1_GAIN_REG and ANALOG_MIC1_GAIN_REG Masks */
+#define MIC_ANALOG_GAIN_MASK 0x1F
+
+/*ANALOG_HS_GAIN_REG and ANALOG_LINE_IN_GAIN_REG Masks*/
+#define L_ANALOG_GAIN_MASK 0xF0
+#define R_ANALOG_GAIN_MASK 0x0F
+
+/* IF0_IF1_MASTER_CONF_REG Masks */
+#define EN_MASTGEN 0x80
+#define BITCLK_OSR_N_64 0x02
+#define BITCLK_OSR_N_128 0x04
+#define BITCLK_OSR_N_256 0x06
+#define EN_FSYNC_BITCLK 0x01
+#define EN_FSYNC_BITCLK1 0x10
+
+/* IF0_CONF_REG and IF1_CONF_REG Masks */
+#define FSYNC_FALLING_EDGE 0x40
+#define BITCLK_FALLING_EDGE 0x20
+#define IF_DELAYED 0x10
+#define I2S_LEFT_ALIGNED_FORMAT 0x08
+#define TDM_FORMAT 0x04
+#define WORD_LENGTH_32 0x03
+#define WORD_LENGTH_24 0x02
+#define WORD_LENGTH_20 0x01
+#define WORD_LENGTH_16 0x00
+
+/* TDM_IF_BYPASS_B_FIFO_REG Masks */
+#define IF0_BFifoEn 0x01
+#define IF0_MASTER 0x02
+
+#define IF1_MASTER 0x20
+/*
+ * AD_ALLOCATION_TO_SLOT0_1_REG and AD_ALLOCATION_TO_SLOT2_3_REG and
+ * AD_ALLOCATION_TO_SLOT4_5_REG and AD_ALLOCATION_TO_SLOT6_7_REG Masks
+ */
+#define DATA_FROM_AD_OUT1 0x00
+#define DATA_FROM_AD_OUT2 0x01
+#define DATA_FROM_AD_OUT3 0x02
+#define DATA_FROM_AD_OUT4 0x03
+#define DATA_FROM_AD_OUT5 0x04
+#define DATA_FROM_AD_OUT6 0x05
+#define DATA_FROM_AD_OUT7 0x06
+#define DATA_FROM_AD_OUT8 0x07
+#define TRISTATE 0x0C
+
+/*
+ * SLOT_SELECTION_TO_DA1_REG and SLOT_SELECTION_TO_DA2_REG and
+ * SLOT_SELECTION_TO_DA3_REG and SLOT_SELECTION_TO_DA4_REG Masks
+ * SLOT_SELECTION_TO_DA5_REG and SLOT_SELECTION_TO_DA6_REG Masks
+ */
+#define SLOT08_FOR_DA_PATH 0x08
+#define SLOT09_FOR_DA_PATH 0x09
+#define SLOT10_FOR_DA_PATH 0x0A
+#define SLOT11_FOR_DA_PATH 0x0B
+#define SLOT12_FOR_DA_PATH 0x0C
+#define SLOT13_FOR_DA_PATH 0x0D
+#define SLOT14_FOR_DA_PATH 0x0E
+#define SLOT15_FOR_DA_PATH 0x0F
+
+/* DIGITAL_MUXES_REG1 Masks */
+#define DA1_TO_HSL 0x80
+#define DA2_TO_HSR 0x40
+#define SEL_DMIC1_FOR_AD_OUT1 0x20
+#define SEL_DMIC2_FOR_AD_OUT2 0x10
+#define SEL_DMIC3_FOR_AD_OUT3 0x08
+/*#define SEL_DMIC5_FOR_AD_OUT5 0x04*/
+/*#define SEL_DMIC6_FOR_AD_OUT6 0x02*/
+/*#define SEL_DMIC1_FOR_AD_OUT1 0x01*/
+
+/*
+ * AD1_DIGITAL_GAIN_REG and AD2_DIGITAL_GAIN_REG & AD3_DIGITAL_GAIN_REG Masks
+ * AD4_DIGITAL_GAIN_REG and AD5_DIGITAL_GAIN_REG & AD6_DIGITAL_GAIN_REG Masks
+ * DA1_DIGITAL_GAIN_REG and DA2_DIGITAL_GAIN_REG & DA3_DIGITAL_GAIN_REG Masks
+ * DA4_DIGITAL_GAIN_REG and DA5_DIGITAL_GAIN_REG & DA6_DIGITAL_GAIN_REG Masks
+ */
+#define DIS_FADING 0x40
+#define DIGITAL_GAIN_MASK 0x3F
+
+/*
+ * HSL_EAR_DIGITAL_GAIN_REG and HSR_DIGITAL_GAIN_REG Masks
+ */
+#define FADE_SPEED_MASK 0xC0
+#define DIS_DIG_GAIN_FADING 0x10
+#define HS_DIGITAL_GAIN_MASK 0x0F
+
+/* FMRx/FMTx Masks */
+#define SLOT24_FOR_DA_PATH 0x18
+#define SEL_AD_OUT8_FROM_DAIN7 0x20
+#define SLOT25_FOR_DA_PATH 0x19
+#define SEL_AD_OUT6_FROM_DAIN8 0x20
+#define SEL_IF8_FROM_AD_OUT7 0x60
+#define SEL_IF17_FROM_AD_OUT7 0x60
+#define SEL_IF16_FROM_AD_OUT8 0x07
+
+#define SEL_IF6_FROM_AD_OUT5 0x04
+#define SEL_IF7_FROM_AD_OUT6 0x50
+#define SEL_IF17_FROM_AD_OUT6 0x50
+#define SEL_AD_OUT5_FROM_DAIN7 0x20
+
+/* Burst FIFO Control Masks */
+#define WAKEUP_SIGNAL_SAMPLE_COUNT 0x1B
+#define BURST_FIFO_TRANSFER_LENGTH 0xC0
+#define BURST_FIFO_INF_RUNNING 0x01
+#define BURST_FIFO_INF_IN_MASTER_MODE 0x02
+#define PRE_BIT_CLK0_COUNT 0x1C
+#define BURST_FIFO_WAKUP_DEALAY 0x70
+
+/* Filter Control Masks */
+/* SideTone Masks */
+#define SIDETONE_DIGITAL_GAIN_MASK 0x1F
+#define FIR1_FROMAD1 0x0C
+#define FIR1_FROMAD2 0x03
+#define FIR1_FROMAD3 0x08
+#define FIR1_DAIN1 0x0C
+
+#define FIR2_FROMAD2 0x00
+#define FIR2_FROMAD3 0x01
+#define FIR2_FROMAD4 0x02
+#define FIR2_DAIN2 0x03
+
+#define FIR2_ANDFIR1AD3 0x09
+#define FIR_FILTERCONTROL 0x04
+#define APPLY_FIR_COEFFS_MASK 0x80
+
+/* IRQ status masks */
+#define NCP_READY_MASK 0x80
+
+/* AB8500 power control Masks */
+#define AB8500_VER_1_0 0x10
+#define AB8500_VER_1_1 0x11
+#define CLK_32K_OUT2_DISABLE 0x01
+#define INACTIVE_RESET_AUDIO 0x02
+#define AB8500_REQ_SYS_CLK 0x08
+#define ENABLE_AUDIO_CLK_TO_AUDIO_BLK 0x10
+#define ENABLE_VINTCORE12_SUPPLY 0x04
+#define VAMIC2_ENABLE 0x10
+#define VAMIC1_ENABLE 0x08
+#define VDMIC_ENABLE 0x04
+#define VAUDIO_ENABLE 0x02
+#define GPIO27_DIR_OUTPUT 0x04
+#define GPIO29_DIR_OUTPUT 0x10
+#define GPIO31_DIR_OUTPUT 0x40
+#define GPIO35_DIR_OUTPUT 0X04
+#endif
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_core.c b/drivers/misc/audio_io_dev/ste_audio_io_core.c
new file mode 100644
index 00000000000..129cd041e24
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_core.c
@@ -0,0 +1,1464 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <mach/ste_audio_io_vibrator.h>
+#include <mach/ste_audio.h>
+
+#include "ste_audio_io_core.h"
+#include "ste_audio_io_hwctrl_common.h"
+#include "ste_audio_io_ab8500_reg_defs.h"
+
+static struct audiocodec_context_t *ptr_audio_codec_cnxt;
+
+static struct clk *clk_ptr_msp1;
+static struct clk *clk_ptr_msp3;
+static struct clk *clk_ptr_sysclk;
+
+static struct regulator *regulator_vdmic;
+static struct regulator *regulator_vaudio;
+static struct regulator *regulator_vamic1;
+static struct regulator *regulator_vamic2;
+struct regulator *regulator_avsource;
+static void ste_audio_io_init_transducer_cnxt(void);
+
+bool ste_audio_io_core_is_ready_for_suspend()
+{
+ bool err = false;
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ if ((!ptr_audio_codec_cnxt->power_client) &&
+ (!ptr_audio_codec_cnxt->audio_codec_powerup))
+ err = true;
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ return err;
+}
+int ste_audio_io_core_api_init_data(struct platform_device *pdev)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+ struct ab8500_platform_data *pdata = dev_get_platdata(ab8500->dev);
+ int status = 0;
+ ptr_audio_codec_cnxt = kmalloc(sizeof(struct audiocodec_context_t),
+ GFP_KERNEL);
+ if (!ptr_audio_codec_cnxt)
+ return -ENOMEM;
+
+ memset(ptr_audio_codec_cnxt, 0, sizeof(*ptr_audio_codec_cnxt));
+ ptr_audio_codec_cnxt->dev = &pdev->dev;
+ mutex_init(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ if (pdata) {
+ if (pdata->audio) {
+ ptr_audio_codec_cnxt->gpio_altf_init =
+ pdata->audio->ste_gpio_altf_init;
+ ptr_audio_codec_cnxt->gpio_altf_exit =
+ pdata->audio->ste_gpio_altf_exit;
+ }
+ }
+
+ regulator_vdmic = regulator_get(NULL, "v-dmic");
+ if (IS_ERR(regulator_vdmic)) {
+ status = PTR_ERR(regulator_vdmic);
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Register error for v-dmic=%d", status);
+ goto free_audio_codec_cnxt;
+ }
+ regulator_vamic1 = regulator_get(NULL, "v-amic1");
+ if (IS_ERR(regulator_vamic1)) {
+ status = PTR_ERR(regulator_vamic1);
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Register error for v-amic1=%d", status);
+ goto free_regulator_vdmic;
+ }
+ regulator_vamic2 = regulator_get(NULL, "v-amic2");
+ if (IS_ERR(regulator_vamic2)) {
+ status = PTR_ERR(regulator_vamic2);
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Register error for v-amic2=%d", status);
+ goto free_regulator_vdmic_vamic1;
+ }
+ regulator_vaudio = regulator_get(NULL, "v-audio");
+ if (IS_ERR(regulator_vaudio)) {
+ status = PTR_ERR(regulator_vaudio);
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Register error for v-audio=%d", status);
+ goto free_regulator_vdmic_vamic1_vamic2;
+ }
+ regulator_avsource = regulator_get(ptr_audio_codec_cnxt->dev,
+ "vcc-N2158");
+ if (IS_ERR(regulator_avsource)) {
+ status = PTR_ERR(regulator_avsource);
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Register error for vcc-N2158=%d", status);
+ goto free_regulator_vdmic_vamic1_vamic2_vaudio;
+ }
+
+ ste_audio_io_init_transducer_cnxt();
+ return 0;
+
+free_regulator_vdmic_vamic1_vamic2_vaudio:
+ regulator_put(regulator_vaudio);
+free_regulator_vdmic_vamic1_vamic2:
+ regulator_put(regulator_vamic2);
+free_regulator_vdmic_vamic1:
+ regulator_put(regulator_vamic1);
+free_regulator_vdmic:
+ regulator_put(regulator_vdmic);
+free_audio_codec_cnxt:
+ kfree(ptr_audio_codec_cnxt);
+ return status;
+}
+
+static struct transducer_context_t transducer_headset = {
+ .pwr_up_func = ste_audio_io_power_up_headset,
+ .pwr_down_func = ste_audio_io_power_down_headset,
+ .set_gain_func = ste_audio_io_set_headset_gain,
+ .get_gain_func = ste_audio_io_get_headset_gain,
+ .mute_func = ste_audio_io_mute_headset,
+ .unmute_func = ste_audio_io_unmute_headset,
+ .enable_fade_func = ste_audio_io_enable_fade_headset,
+ .disable_fade_func = ste_audio_io_disable_fade_headset,
+ .switch_to_burst_func = ste_audio_io_switch_to_burst_mode_headset,
+ .switch_to_normal_func = ste_audio_io_switch_to_normal_mode_headset
+};
+
+static struct transducer_context_t transducer_earpiece = {
+ .pwr_up_func = ste_audio_io_power_up_earpiece,
+ .pwr_down_func = ste_audio_io_power_down_earpiece,
+ .set_gain_func = ste_audio_io_set_earpiece_gain,
+ .get_gain_func = ste_audio_io_get_earpiece_gain,
+ .mute_func = ste_audio_io_mute_earpiece,
+ .unmute_func = ste_audio_io_unmute_earpiece,
+ .enable_fade_func = ste_audio_io_enable_fade_earpiece,
+ .disable_fade_func = ste_audio_io_disable_fade_earpiece
+};
+
+static struct transducer_context_t transducer_ihf = {
+ .pwr_up_func = ste_audio_io_power_up_ihf,
+ .pwr_down_func = ste_audio_io_power_down_ihf,
+ .set_gain_func = ste_audio_io_set_ihf_gain,
+ .get_gain_func = ste_audio_io_get_ihf_gain,
+ .mute_func = ste_audio_io_mute_ihf,
+ .unmute_func = ste_audio_io_unmute_ihf,
+ .enable_fade_func = ste_audio_io_enable_fade_ihf,
+ .disable_fade_func = ste_audio_io_disable_fade_ihf
+
+};
+
+static struct transducer_context_t transducer_vibl = {
+ .pwr_up_func = ste_audio_io_power_up_vibl,
+ .pwr_down_func = ste_audio_io_power_down_vibl,
+ .set_gain_func = ste_audio_io_set_vibl_gain,
+ .get_gain_func = ste_audio_io_get_vibl_gain,
+ .mute_func = ste_audio_io_mute_vibl,
+ .unmute_func = ste_audio_io_unmute_vibl,
+ .enable_fade_func = ste_audio_io_enable_fade_vibl,
+ .disable_fade_func = ste_audio_io_disable_fade_vibl
+};
+
+static struct transducer_context_t transducer_vibr = {
+ .pwr_up_func = ste_audio_io_power_up_vibr,
+ .pwr_down_func = ste_audio_io_power_down_vibr,
+ .set_gain_func = ste_audio_io_set_vibr_gain,
+ .get_gain_func = ste_audio_io_get_vibr_gain,
+ .mute_func = ste_audio_io_mute_vibr,
+ .unmute_func = ste_audio_io_unmute_vibr,
+ .enable_fade_func = ste_audio_io_enable_fade_vibr,
+ .disable_fade_func = ste_audio_io_disable_fade_vibr
+};
+
+static struct transducer_context_t transducer_mic1a = {
+ .pwr_up_func = ste_audio_io_power_up_mic1a,
+ .pwr_down_func = ste_audio_io_power_down_mic1a,
+ .set_gain_func = ste_audio_io_set_mic1a_gain,
+ .get_gain_func = ste_audio_io_get_mic1a_gain,
+ .mute_func = ste_audio_io_mute_mic1a,
+ .unmute_func = ste_audio_io_unmute_mic1a,
+ .enable_fade_func = ste_audio_io_enable_fade_mic1a,
+ .disable_fade_func = ste_audio_io_disable_fade_mic1a
+};
+
+static struct transducer_context_t transducer_mic1b = {
+ .pwr_up_func = ste_audio_io_power_up_mic1b,
+ .pwr_down_func = ste_audio_io_power_down_mic1b,
+ .set_gain_func = ste_audio_io_set_mic1a_gain,
+ .get_gain_func = ste_audio_io_get_mic1a_gain,
+ .mute_func = ste_audio_io_mute_mic1a,
+ .unmute_func = ste_audio_io_unmute_mic1a,
+ .enable_fade_func = ste_audio_io_enable_fade_mic1a,
+ .disable_fade_func = ste_audio_io_disable_fade_mic1a,
+ .enable_loop = ste_audio_io_enable_loop_mic1b,
+ .disable_loop = ste_audio_io_disable_loop_mic1b
+};
+
+static struct transducer_context_t transducer_mic2 = {
+ .pwr_up_func = ste_audio_io_power_up_mic2,
+ .pwr_down_func = ste_audio_io_power_down_mic2,
+ .set_gain_func = ste_audio_io_set_mic2_gain,
+ .get_gain_func = ste_audio_io_get_mic2_gain,
+ .mute_func = ste_audio_io_mute_mic2,
+ .unmute_func = ste_audio_io_unmute_mic2,
+ .enable_fade_func = ste_audio_io_enable_fade_mic2,
+ .disable_fade_func = ste_audio_io_disable_fade_mic2
+};
+
+static struct transducer_context_t transducer_lin = {
+ .pwr_up_func = ste_audio_io_power_up_lin,
+ .pwr_down_func = ste_audio_io_power_down_lin,
+ .set_gain_func = ste_audio_io_set_lin_gain,
+ .get_gain_func = ste_audio_io_get_lin_gain,
+ .mute_func = ste_audio_io_mute_lin,
+ .unmute_func = ste_audio_io_unmute_lin,
+ .enable_fade_func = ste_audio_io_enable_fade_lin,
+ .disable_fade_func = ste_audio_io_disable_fade_lin
+};
+
+static struct transducer_context_t transducer_dmic12 = {
+ .pwr_up_func = ste_audio_io_power_up_dmic12,
+ .pwr_down_func = ste_audio_io_power_down_dmic12,
+ .set_gain_func = ste_audio_io_set_dmic12_gain,
+ .get_gain_func = ste_audio_io_get_dmic12_gain,
+ .mute_func = ste_audio_io_mute_dmic12,
+ .unmute_func = ste_audio_io_unmute_dmic12,
+ .enable_fade_func = ste_audio_io_enable_fade_dmic12,
+ .disable_fade_func = ste_audio_io_disable_fade_dmic12,
+ .enable_loop = ste_audio_io_enable_loop_dmic12,
+ .disable_loop = ste_audio_io_disable_loop_dmic12
+};
+
+static struct transducer_context_t transducer_dmic34 = {
+ .pwr_up_func = ste_audio_io_power_up_dmic34,
+ .pwr_down_func = ste_audio_io_power_down_dmic34,
+ .set_gain_func = ste_audio_io_set_dmic34_gain,
+ .get_gain_func = ste_audio_io_get_dmic34_gain,
+ .mute_func = ste_audio_io_mute_dmic34,
+ .unmute_func = ste_audio_io_unmute_dmic34,
+ .enable_fade_func = ste_audio_io_enable_fade_dmic34,
+ .disable_fade_func = ste_audio_io_disable_fade_dmic34
+};
+
+static struct transducer_context_t transducer_dmic56 = {
+ .pwr_up_func = ste_audio_io_power_up_dmic56,
+ .pwr_down_func = ste_audio_io_power_down_dmic56,
+ .set_gain_func = ste_audio_io_set_dmic56_gain,
+ .get_gain_func = ste_audio_io_get_dmic56_gain,
+ .mute_func = ste_audio_io_mute_dmic56,
+ .unmute_func = ste_audio_io_unmute_dmic56,
+ .enable_fade_func = ste_audio_io_enable_fade_dmic56,
+ .disable_fade_func = ste_audio_io_disable_fade_dmic56,
+};
+
+static struct transducer_context_t transducer_fmrx = {
+ .pwr_up_func = ste_audio_io_power_up_fmrx,
+ .pwr_down_func = ste_audio_io_power_down_fmrx,
+};
+
+static struct transducer_context_t transducer_fmtx = {
+ .pwr_up_func = ste_audio_io_power_up_fmtx,
+ .pwr_down_func = ste_audio_io_power_down_fmtx,
+};
+
+static struct transducer_context_t transducer_bluetooth = {
+ .pwr_up_func = ste_audio_io_power_up_bluetooth,
+ .pwr_down_func = ste_audio_io_power_down_bluetooth,
+};
+
+static void ste_audio_io_init_transducer_cnxt(void)
+{
+ ptr_audio_codec_cnxt->transducer[HS_CH] = &transducer_headset;
+ ptr_audio_codec_cnxt->transducer[EAR_CH] = &transducer_earpiece;
+ ptr_audio_codec_cnxt->transducer[IHF_CH] = &transducer_ihf;
+ ptr_audio_codec_cnxt->transducer[VIBL_CH] = &transducer_vibl;
+ ptr_audio_codec_cnxt->transducer[VIBR_CH] = &transducer_vibr;
+ ptr_audio_codec_cnxt->transducer[MIC1A_CH] = &transducer_mic1a;
+ ptr_audio_codec_cnxt->transducer[MIC1B_CH] = &transducer_mic1b;
+ ptr_audio_codec_cnxt->transducer[MIC2_CH] = &transducer_mic2;
+ ptr_audio_codec_cnxt->transducer[LIN_CH] = &transducer_lin;
+ ptr_audio_codec_cnxt->transducer[DMIC12_CH] = &transducer_dmic12;
+ ptr_audio_codec_cnxt->transducer[DMIC34_CH] = &transducer_dmic34;
+ ptr_audio_codec_cnxt->transducer[DMIC56_CH] = &transducer_dmic56;
+ ptr_audio_codec_cnxt->transducer[FMRX_CH] = &transducer_fmrx;
+ ptr_audio_codec_cnxt->transducer[FMTX_CH] = &transducer_fmtx;
+ ptr_audio_codec_cnxt->transducer[BLUETOOTH_CH] = &transducer_bluetooth;
+}
+
+void ste_audio_io_core_api_free_data(void)
+{
+ regulator_put(regulator_vdmic);
+ regulator_put(regulator_vamic1);
+ regulator_put(regulator_vamic2);
+ regulator_put(regulator_vaudio);
+ regulator_put(regulator_avsource);
+ kfree(ptr_audio_codec_cnxt);
+}
+
+static int ste_audio_io_core_api_enable_regulators(int channel_type)
+{
+ int error = 0;
+
+ switch (channel_type) {
+ case EAR_CH:
+ case HS_CH:
+ case IHF_CH:
+ case VIBL_CH:
+ case VIBR_CH:
+ case LIN_CH:
+ case FMRX_CH:
+ case FMTX_CH:
+ case BLUETOOTH_CH:
+ /* vaduio already enabled
+ no additional regualtor required */
+ break;
+
+ case MIC1A_CH:
+ case MIC1B_CH:
+ error = regulator_enable(regulator_vamic1);
+ if (error)
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "unable to enable regulator vamic1 error = %d", error);
+ break;
+
+ case MIC2_CH:
+ error = regulator_enable(regulator_vamic2);
+ if (error)
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "unable to enable regulator vamic2 error = %d", error);
+ break;
+
+ case DMIC12_CH:
+ case DMIC34_CH:
+ case DMIC56_CH:
+ case MULTI_MIC_CH:
+ error = regulator_enable(regulator_vdmic);
+ if (error)
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "unable to enable regulator vdmic error = %d", error);
+ }
+ return error;
+}
+
+static int ste_audio_io_core_api_disable_regulators(int channel_type)
+{
+ int error = 0;
+
+ switch (channel_type) {
+ case EAR_CH:
+ case HS_CH:
+ case IHF_CH:
+ case VIBL_CH:
+ case VIBR_CH:
+ case LIN_CH:
+ case FMRX_CH:
+ case FMTX_CH:
+ case BLUETOOTH_CH:
+ /* no need to disable separately*/
+ break;
+
+ case MIC1A_CH:
+ case MIC1B_CH:
+ error = regulator_disable(regulator_vamic1);
+ if (error)
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "unable to disable regulator vamic1 error = %d", error);
+ break;
+
+ case MIC2_CH:
+ error = regulator_disable(regulator_vamic2);
+ if (error)
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "unable to disable regulator vamic2 error = %d", error);
+ break;
+
+ case DMIC12_CH:
+ case DMIC34_CH:
+ case DMIC56_CH:
+ case MULTI_MIC_CH:
+ error = regulator_disable(regulator_vdmic);
+ if (error)
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "unable to disable regulator vdmic error = %d", error);
+ }
+ return error;
+}
+
+int ste_audio_io_core_api_powerup_audiocodec(int power_client)
+{
+ int error = 0;
+ int acodec_device_id;
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ acodec_device_id = abx500_get_chip_id(&ste_audio_io_device->dev);
+
+ /*
+ * If there is no power client registered, power up
+ * common audio blocks for audio and vibrator
+ */
+ if (!ptr_audio_codec_cnxt->power_client) {
+ __u8 data, old_data;
+
+ old_data = HW_REG_READ(AB8500_CTRL3_REG);
+
+ /* Enable 32 Khz clock signal on Clk32KOut2 ball */
+ data = (~CLK_32K_OUT2_DISABLE) & old_data;
+ error = HW_REG_WRITE(AB8500_CTRL3_REG, data);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "enabling 32KHz clock error = %d", error);
+ goto err_cleanup;
+ }
+ data = INACTIVE_RESET_AUDIO | old_data;
+ error = HW_REG_WRITE(AB8500_CTRL3_REG, data);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "deactivate audio codec reset error = %d", error);
+ goto err_cleanup;
+ }
+ old_data = HW_REG_READ(AB8500_SYSULPCLK_CTRL1_REG);
+ data = ENABLE_AUDIO_CLK_TO_AUDIO_BLK | old_data;
+
+ error = HW_REG_WRITE(AB8500_SYSULPCLK_CTRL1_REG, data);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "enabling clock to audio block error = %d", error);
+ goto err_cleanup;
+ }
+ regulator_enable(regulator_vaudio);
+
+ old_data = HW_REG_READ(AB8500_GPIO_DIR4_REG);
+ data = (GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
+ GPIO31_DIR_OUTPUT) | old_data;
+ error = HW_REG_WRITE(AB8500_GPIO_DIR4_REG, data);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "setting gpio dir4 error = %d", error);
+ goto err_cleanup;
+ }
+ error = HW_REG_WRITE(SOFTWARE_RESET_REG, SW_RESET);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Software reset error=%d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(POWER_UP_CONTROL_REG,
+ (DEVICE_POWER_UP|ANALOG_PARTS_POWER_UP), 0);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Device Power Up, error=%d", error);
+ goto err_cleanup;
+ }
+ }
+ /* Save information that given client already powered up audio block */
+ ptr_audio_codec_cnxt->power_client |= power_client;
+
+ /* If audio block requested power up, turn on additional audio blocks */
+ if (power_client == STE_AUDIOIO_POWER_AUDIO) {
+ if (!ptr_audio_codec_cnxt->audio_codec_powerup) {
+ clk_ptr_sysclk =
+ clk_get(ptr_audio_codec_cnxt->dev, "sysclk");
+ if (!IS_ERR(clk_ptr_sysclk)) {
+ error = clk_enable(clk_ptr_sysclk);
+ if (error)
+ goto err_cleanup;
+ } else {
+ error = -EFAULT;
+ goto err_cleanup;
+ }
+
+ clk_ptr_msp1 = clk_get_sys("msp1", NULL);
+ if (!IS_ERR(clk_ptr_msp1)) {
+ error = clk_enable(clk_ptr_msp1);
+ if (error)
+ goto err_cleanup;
+ } else {
+ error = -EFAULT;
+ goto err_cleanup;
+ }
+
+ if (AB8500_REV_20 == acodec_device_id) {
+ clk_ptr_msp3 = clk_get_sys("msp3", NULL);
+ if (!IS_ERR(clk_ptr_msp3)) {
+ error = clk_enable(clk_ptr_msp3);
+ if (error)
+ goto err_cleanup;
+ } else {
+ error = -EFAULT;
+ goto err_cleanup;
+ }
+ }
+
+ if (ptr_audio_codec_cnxt->gpio_altf_init) {
+ error = ptr_audio_codec_cnxt->gpio_altf_init();
+ if (error)
+ goto err_cleanup;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(IF0_IF1_MASTER_CONF_REG,
+ EN_MASTGEN, 0);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Enable Master Generator, error=%d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(TDM_IF_BYPASS_B_FIFO_REG,
+ IF0_MASTER, 0);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "IF0: Master Mode, error=%d", error);
+ goto err_cleanup;
+ }
+
+ /* Configuring IF0 */
+
+ error = HW_ACODEC_MODIFY_WRITE(IF0_IF1_MASTER_CONF_REG,
+ BITCLK_OSR_N_256, 0);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "IF0: Enable FsBitClk & FSync error=%d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_REG_WRITE(IF0_CONF_REG, IF_DELAYED
+ | TDM_FORMAT | WORD_LENGTH_20);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "IF0: TDM Format 16 Bits word length, error=%d",
+ error);
+ goto err_cleanup;
+ }
+ }
+ ptr_audio_codec_cnxt->audio_codec_powerup++;
+ }
+err_cleanup:
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ return error;
+}
+
+int ste_audio_io_core_api_powerdown_audiocodec(int power_client)
+{
+ int error = 0;
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ /* Update power client status */
+ if (power_client == STE_AUDIOIO_POWER_AUDIO) {
+ ptr_audio_codec_cnxt->audio_codec_powerup--;
+ if (!ptr_audio_codec_cnxt->audio_codec_powerup) {
+ ptr_audio_codec_cnxt->power_client &= ~power_client;
+ clk_disable(clk_ptr_sysclk);
+ clk_put(clk_ptr_sysclk);
+ clk_disable(clk_ptr_msp1);
+ clk_put(clk_ptr_msp1);
+ if (AB8500_REV_20 ==
+ abx500_get_chip_id(&ste_audio_io_device->dev)) {
+ clk_disable(clk_ptr_msp3);
+ clk_put(clk_ptr_msp3);
+ }
+
+ if (ptr_audio_codec_cnxt->gpio_altf_exit) {
+ error = ptr_audio_codec_cnxt->gpio_altf_exit();
+ if (error)
+ goto err_cleanup;
+ }
+ }
+ } else
+ ptr_audio_codec_cnxt->power_client &= ~power_client;
+
+ /* If no power client registered, power down audio block */
+ if (!ptr_audio_codec_cnxt->power_client) {
+ regulator_disable(regulator_vaudio);
+ if (error != 0) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Device Power Down and Analog Parts Power Down error = %d ",
+ error);
+ goto err_cleanup;
+ }
+ }
+
+err_cleanup:
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ return error;
+}
+/**
+ * @brief Read from AB8500 device
+ * @dev_data Pointer to the structure __audioio_data
+ * @return 0
+ */
+
+int ste_audio_io_core_api_access_read(struct audioio_data_t *dev_data)
+{
+ int reg;
+ if (NULL == dev_data)
+ return -EFAULT;
+ reg = (dev_data->block<<8)|(dev_data->addr&0xff);
+ dev_data->data = HW_REG_READ(reg);
+ return 0;
+}
+/**
+ * @brief Write on AB8500 device
+ * @dev_data Pointer to the structure __audioio_data
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_core_api_access_write(struct audioio_data_t *dev_data)
+{
+ int retval, reg;
+ if (NULL == dev_data)
+ return -EFAULT;
+
+ reg = (dev_data->block<<8)|(dev_data->addr&0xff);
+ retval = HW_REG_WRITE(reg, dev_data->data);
+
+ return retval;
+}
+/**
+ * @brief Store the power and mute status of transducer
+ * @channel_index Channel-index of transducer
+ * @ptr Array storing the status
+ * @value status being stored
+ * @return 0 on success otherwise negative error code
+ */
+
+void ste_audio_io_core_api_store_data(enum AUDIOIO_CH_INDEX channel_index,
+ int *ptr, int value)
+{
+ if (channel_index & e_CHANNEL_1)
+ ptr[0] = value;
+
+ if (channel_index & e_CHANNEL_2)
+ ptr[1] = value;
+
+ if (channel_index & e_CHANNEL_3)
+ ptr[2] = value;
+
+ if (channel_index & e_CHANNEL_4)
+ ptr[3] = value;
+}
+/**
+ * @brief Get power or mute status on a specific channel
+ * @channel_index Channel-index of the transducer
+ * @ptr Pointer to is_power_up array or is_muted array
+ * @return status of control switch
+ */
+enum AUDIOIO_COMMON_SWITCH ste_audio_io_core_api_get_status(
+ enum AUDIOIO_CH_INDEX channel_index, int *ptr)
+{
+ if (channel_index & e_CHANNEL_1) {
+ if (AUDIOIO_TRUE == ptr[0])
+ return AUDIOIO_COMMON_ON;
+ else
+ return AUDIOIO_COMMON_OFF;
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ if (AUDIOIO_TRUE == ptr[1])
+ return AUDIOIO_COMMON_ON;
+ else
+ return AUDIOIO_COMMON_OFF;
+ }
+
+ if (channel_index & e_CHANNEL_3) {
+ if (AUDIOIO_TRUE == ptr[2])
+ return AUDIOIO_COMMON_ON;
+ else
+ return AUDIOIO_COMMON_OFF;
+ }
+
+ if (channel_index & e_CHANNEL_4) {
+ if (AUDIOIO_TRUE == ptr[3])
+ return AUDIOIO_COMMON_ON;
+ else
+ return AUDIOIO_COMMON_OFF;
+ }
+ return 0;
+}
+
+int ste_audio_io_core_api_acodec_power_control(struct audioio_acodec_pwr_ctrl_t
+ *audio_acodec_pwr_ctrl)
+{
+ int error = 0;
+ if (audio_acodec_pwr_ctrl->ctrl_switch == AUDIOIO_COMMON_ON)
+ error = ste_audio_io_core_api_powerup_audiocodec(
+ STE_AUDIOIO_POWER_AUDIO);
+ else
+ error = ste_audio_io_core_api_powerdown_audiocodec(
+ STE_AUDIOIO_POWER_AUDIO);
+
+ return error;
+}
+/**
+ * @brief Control for powering on/off HW components on a specific channel
+ * @pwr_ctrl Pointer to the structure __audioio_pwr_ctrl
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_core_api_power_control_transducer(
+ struct audioio_pwr_ctrl_t *pwr_ctrl)
+{
+ int error = 0;
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+
+ channel_index = pwr_ctrl->channel_index;
+
+ if ((pwr_ctrl->channel_type < FIRST_CH)
+ || (pwr_ctrl->channel_type > LAST_CH))
+ return -EINVAL;
+
+ ptr = ptr_audio_codec_cnxt->transducer[pwr_ctrl->channel_type];
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ if (AUDIOIO_COMMON_ON == pwr_ctrl->ctrl_switch) {
+ if (ptr->pwr_up_func) {
+ error = ste_audio_io_core_api_enable_regulators(
+ pwr_ctrl->channel_type);
+ if (error)
+ goto free_mutex;
+
+ error = ptr->pwr_up_func(pwr_ctrl->channel_index,
+ ptr_audio_codec_cnxt->dev);
+ if (0 == error) {
+ ste_audio_io_core_api_store_data(channel_index,
+ ptr->is_power_up, AUDIOIO_TRUE);
+ }
+ }
+ } else {
+ if (ptr->pwr_down_func) {
+ error = ptr->pwr_down_func(pwr_ctrl->channel_index,
+ ptr_audio_codec_cnxt->dev);
+ if (0 == error) {
+ ste_audio_io_core_api_store_data(channel_index,
+ ptr->is_power_up, AUDIOIO_FALSE);
+ }
+ error = ste_audio_io_core_api_disable_regulators(
+ pwr_ctrl->channel_type);
+ }
+ }
+
+free_mutex:
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+/**
+ * @brief Query power state of HW path on specified channel
+ * @pwr_ctrl Pointer to the structure __audioio_pwr_ctrl
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_core_api_power_status_transducer(
+ struct audioio_pwr_ctrl_t *pwr_ctrl)
+{
+
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+
+ channel_index = pwr_ctrl->channel_index;
+
+ if ((pwr_ctrl->channel_type < FIRST_CH)
+ || (pwr_ctrl->channel_type > LAST_CH))
+ return -EINVAL;
+
+ ptr = ptr_audio_codec_cnxt->transducer[pwr_ctrl->channel_type];
+
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+
+ pwr_ctrl->ctrl_switch = ste_audio_io_core_api_get_status(channel_index,
+ ptr->is_power_up);
+
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return 0;
+
+}
+
+int ste_audio_io_core_api_loop_control(struct audioio_loop_ctrl_t *loop_ctrl)
+{
+ int error = 0;
+ struct transducer_context_t *ptr = NULL;
+
+ if ((loop_ctrl->channel_type < FIRST_CH)
+ || (loop_ctrl->channel_type > LAST_CH))
+ return -EINVAL;
+
+ ptr = ptr_audio_codec_cnxt->transducer[loop_ctrl->channel_type];
+
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ if (AUDIOIO_COMMON_ON == loop_ctrl->ctrl_switch) {
+ if (ptr->enable_loop) {
+ error = ptr->enable_loop(loop_ctrl->channel_index,
+ loop_ctrl->hw_loop,
+ loop_ctrl->loop_gain,
+ ptr_audio_codec_cnxt->dev,
+ ptr_audio_codec_cnxt->transducer);
+ if (error)
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Loop enable failed for hw loop = %d, error = %d ",
+ (int)loop_ctrl->hw_loop, error);
+ } else {
+ error = -EFAULT;
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Hw Loop enable does not exist for channel= %d, error = %d ",
+ (int)loop_ctrl->channel_type, error);
+ }
+ } else {
+ if (ptr->disable_loop) {
+ error = ptr->disable_loop(loop_ctrl->channel_index,
+ loop_ctrl->hw_loop,
+ ptr_audio_codec_cnxt->dev,
+ ptr_audio_codec_cnxt->transducer);
+ if (error)
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Loop disable failed for hw loop = %d, error = %d ",
+ (int)loop_ctrl->hw_loop, error);
+ } else {
+ error = -EFAULT;
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Hw Loop disable does not exist for channel= %d, error = %d ",
+ (int)loop_ctrl->channel_type, error);
+ }
+ }
+
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+
+int ste_audio_io_core_api_loop_status(struct audioio_loop_ctrl_t *loop_ctrl)
+{
+ return 0;
+}
+
+int ste_audio_io_core_api_get_transducer_gain_capability(
+ struct audioio_get_gain_t *get_gain)
+{
+ return 0;
+}
+
+int ste_audio_io_core_api_gain_capabilities_loop(
+ struct audioio_gain_loop_t *gain_loop)
+{
+ if ((gain_loop->channel_type < FIRST_CH)
+ || (gain_loop->channel_type > LAST_CH))
+ return -EINVAL;
+
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ gain_loop->num_loop =
+ transducer_max_no_Of_supported_loops[gain_loop->channel_type];
+ gain_loop->max_gains = max_no_of_loop_gains[gain_loop->channel_type];
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ return 0;
+}
+
+int ste_audio_io_core_api_supported_loops(
+ struct audioio_support_loop_t *support_loop)
+{
+ if ((support_loop->channel_type < FIRST_CH)
+ || (support_loop->channel_type > LAST_CH))
+ return -EINVAL;
+
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ support_loop->spprtd_loop_index =
+ transducer_no_Of_supported_loop_indexes[support_loop->channel_type];
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ return 0;
+}
+
+int ste_audio_io_core_api_gain_descriptor_transducer(
+ struct audioio_gain_desc_trnsdr_t *gdesc_trnsdr)
+{
+ return 0;
+}
+/**
+ * @brief Control for muting a specific channel in HW
+ * @mute_trnsdr Pointer to the structure __audioio_mute_trnsdr
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_core_api_mute_control_transducer(
+ struct audioio_mute_trnsdr_t *mute_trnsdr)
+{
+ int error = 0;
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+
+ channel_index = mute_trnsdr->channel_index;
+
+ if ((mute_trnsdr->channel_type < FIRST_CH)
+ || (mute_trnsdr->channel_type > LAST_CH))
+ return -EINVAL;
+
+ ptr = ptr_audio_codec_cnxt->transducer[mute_trnsdr->channel_type];
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ if (AUDIOIO_COMMON_ON == mute_trnsdr->ctrl_switch) {
+ if (ptr->mute_func) {
+ error = ptr->mute_func(mute_trnsdr->channel_index,
+ ptr_audio_codec_cnxt->dev);
+ if (0 == error) {
+ ste_audio_io_core_api_store_data(channel_index ,
+ ptr->is_muted, AUDIOIO_TRUE);
+ }
+ }
+ } else {
+ if (ptr->unmute_func) {
+ if (0 == ptr->unmute_func(channel_index, ptr->gain,
+ ptr_audio_codec_cnxt->dev)) {
+ ste_audio_io_core_api_store_data(channel_index,
+ ptr->is_muted, AUDIOIO_FALSE);
+ }
+ }
+ }
+
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+/**
+ * @brief Query state of mute on specified channel
+ * @mute_trnsdr Pointer to the structure __audioio_mute_trnsdr
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_core_api_mute_status_transducer(
+ struct audioio_mute_trnsdr_t *mute_trnsdr)
+{
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+
+ channel_index = mute_trnsdr->channel_index;
+
+ if ((mute_trnsdr->channel_type < FIRST_CH)
+ || (mute_trnsdr->channel_type > LAST_CH))
+ return -EINVAL;
+
+ ptr = ptr_audio_codec_cnxt->transducer[mute_trnsdr->channel_type];
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ mute_trnsdr->ctrl_switch = ste_audio_io_core_api_get_status(
+ channel_index, ptr->is_muted);
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return 0;
+}
+/**
+ * @brief control the fading on the transducer called on.
+ * @fade_ctrl Pointer to the structure __audioio_fade_ctrl
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_core_api_fading_control(struct audioio_fade_ctrl_t *fade_ctrl)
+{
+ int error = 0;
+ struct transducer_context_t *ptr = NULL;
+
+ if ((fade_ctrl->channel_type < FIRST_CH)
+ || (fade_ctrl->channel_type > LAST_CH))
+ return -EINVAL;
+ ptr = ptr_audio_codec_cnxt->transducer[fade_ctrl->channel_type];
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ if (AUDIOIO_COMMON_ON == fade_ctrl->ctrl_switch)
+ error = ptr->enable_fade_func(ptr_audio_codec_cnxt->dev);
+
+ else
+ error = ptr->disable_fade_func(ptr_audio_codec_cnxt->dev);
+
+
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+/**
+ * @brief control the low power mode of headset.
+ * @burst_ctrl Pointer to the structure __audioio_burst_ctrl
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_core_api_burstmode_control(
+ struct audioio_burst_ctrl_t *burst_ctrl)
+{
+ int error = 0;
+ struct transducer_context_t *ptr = NULL;
+ int burst_fifo_switch_frame;
+
+ burst_fifo_switch_frame = burst_ctrl->burst_fifo_switch_frame;
+
+ if ((burst_ctrl->channel_type < FIRST_CH)
+ || (burst_ctrl->channel_type > LAST_CH))
+ return -EINVAL;
+ ptr = ptr_audio_codec_cnxt->transducer[burst_ctrl->channel_type];
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ if (AUDIOIO_COMMON_ON == burst_ctrl->ctrl_switch) {
+ if (ptr->switch_to_burst_func)
+ error = ptr->switch_to_burst_func(
+ burst_fifo_switch_frame,
+ ptr_audio_codec_cnxt->dev);
+ } else
+ if (ptr->switch_to_normal_func)
+ error = ptr->switch_to_normal_func(
+ ptr_audio_codec_cnxt->dev);
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+/**
+ * @brief Convert channel index to array index
+ * @channel_index Channel Index of transducer
+ * @return Array index corresponding to the specified channel index
+ */
+
+int convert_channel_index_to_array_index(enum AUDIOIO_CH_INDEX channel_index)
+{
+ if (channel_index & e_CHANNEL_1)
+ return 0;
+ else if (channel_index & e_CHANNEL_2)
+ return 1;
+ else if (channel_index & e_CHANNEL_3)
+ return 2;
+ else
+ return 3;
+}
+
+/**
+ * @brief Set individual gain along the HW path of a specified channel
+ * @gctrl_trnsdr Pointer to the structure __audioio_gain_ctrl_trnsdr
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_core_api_gain_control_transducer(
+ struct audioio_gain_ctrl_trnsdr_t *gctrl_trnsdr)
+{
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+ int ch_array_index;
+ u16 gain_index;
+ int gain_value;
+ u32 linear;
+ int channel_type;
+ int error;
+ int min_gain, max_gain, gain;
+
+ if ((gctrl_trnsdr->channel_type < FIRST_CH)
+ || (gctrl_trnsdr->channel_type > LAST_CH))
+ return -EINVAL;
+
+ if (gctrl_trnsdr->gain_index >= MAX_NO_GAINS)
+ return -EINVAL;
+
+ ptr = ptr_audio_codec_cnxt->transducer[gctrl_trnsdr->channel_type];
+ channel_index = gctrl_trnsdr->channel_index;
+ gain_index = gctrl_trnsdr->gain_index;
+ gain_value = gctrl_trnsdr->gain_value;
+ linear = gctrl_trnsdr->linear;
+ channel_type = gctrl_trnsdr->channel_type;
+
+ ch_array_index = convert_channel_index_to_array_index(channel_index);
+ if (linear) { /* Gain is in the range 0 to 100 */
+ min_gain = gain_descriptor[channel_type]\
+ [ch_array_index][gain_index].min_gain;
+ max_gain = gain_descriptor[channel_type]\
+ [ch_array_index][gain_index].max_gain;
+
+ gain = ((gain_value * (max_gain - min_gain))/100) + min_gain;
+ } else
+ /* Convert to db */
+ gain = gain_value/100;
+
+ gain_value = gain;
+
+#if 1
+ if (gain_index >= transducer_no_of_gains[channel_type])
+ return -EINVAL;
+
+ if (gain_value < gain_descriptor[channel_type]\
+ [ch_array_index][gain_index].min_gain)
+ return -EINVAL;
+
+ if (gain_value > gain_descriptor[channel_type]\
+ [ch_array_index][gain_index].max_gain)
+ return -EINVAL;
+
+#endif
+
+ /* aquire mutex */
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ error = ptr->set_gain_func(channel_index,
+ gain_index, gain_value, linear,
+ ptr_audio_codec_cnxt->dev);
+ if (0 == error)
+ ste_audio_io_core_api_store_data(channel_index ,
+ ptr->gain, gain_value);
+
+
+ /* release mutex */
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ return error;
+}
+/**
+ * @brief Get individual gain along the HW path of a specified channel
+ * @gctrl_trnsdr Pointer to the structure __audioio_gain_ctrl_trnsdr
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_core_api_gain_query_transducer(
+ struct audioio_gain_ctrl_trnsdr_t *gctrl_trnsdr)
+{
+ struct transducer_context_t *ptr = NULL;
+ enum AUDIOIO_CH_INDEX channel_index;
+ u16 gain_index;
+ u32 linear;
+ int left_volume, right_volume;
+ int max_gain, min_gain;
+ int ch_array_index;
+
+ if ((gctrl_trnsdr->channel_type < FIRST_CH)
+ || (gctrl_trnsdr->channel_type > LAST_CH))
+ return -EINVAL;
+
+ if (gctrl_trnsdr->gain_index >= MAX_NO_GAINS)
+ return -EINVAL;
+
+ ptr = ptr_audio_codec_cnxt->transducer[gctrl_trnsdr->channel_type];
+
+ channel_index = gctrl_trnsdr->channel_index;
+ gain_index = gctrl_trnsdr->gain_index;
+ linear = gctrl_trnsdr->linear;
+
+ ptr->get_gain_func(&left_volume, &right_volume, gain_index,
+ ptr_audio_codec_cnxt->dev);
+
+ ch_array_index = convert_channel_index_to_array_index(channel_index);
+ max_gain = gain_descriptor[gctrl_trnsdr->channel_type]\
+ [ch_array_index][gain_index].max_gain;
+ min_gain = gain_descriptor[gctrl_trnsdr->channel_type]\
+ [ch_array_index][gain_index].min_gain;
+
+ switch (channel_index) {
+ case e_CHANNEL_1:
+ gctrl_trnsdr->gain_value = linear ? \
+ min_gain+left_volume*(max_gain-min_gain)/100 : left_volume;
+ break;
+ case e_CHANNEL_2:
+ gctrl_trnsdr->gain_value = linear ? \
+ min_gain+right_volume*(max_gain-min_gain)/100 : right_volume;
+ break;
+ case e_CHANNEL_3:
+ break;
+ case e_CHANNEL_4:
+ break;
+ case e_CHANNEL_ALL:
+ if (left_volume == right_volume) {
+ if (linear)
+ gctrl_trnsdr->gain_value =
+ min_gain+right_volume*(max_gain-min_gain)/100;
+ else
+ gctrl_trnsdr->gain_value = right_volume;
+ }
+ }
+
+ return 0;
+}
+
+
+int ste_audio_io_core_api_fsbitclk_control(
+ struct audioio_fsbitclk_ctrl_t *fsbitclk_ctrl)
+{
+ int error = 0;
+
+ if (AUDIOIO_COMMON_ON == fsbitclk_ctrl->ctrl_switch)
+ error = HW_ACODEC_MODIFY_WRITE(IF0_IF1_MASTER_CONF_REG,
+ EN_FSYNC_BITCLK, 0);
+ else
+ error = HW_ACODEC_MODIFY_WRITE(IF0_IF1_MASTER_CONF_REG, 0,
+ EN_FSYNC_BITCLK);
+
+ return error;
+}
+int ste_audio_io_core_api_pseudoburst_control(
+ struct audioio_pseudoburst_ctrl_t *pseudoburst_ctrl)
+{
+ int error = 0;
+
+ return error;
+}
+int ste_audio_io_core_debug(int x)
+{
+ debug_audioio(x);
+
+return 0;
+}
+
+/**
+ * ste_audioio_vibrator_alloc()
+ * @client: Client id which allocates vibrator
+ * @mask: Mask against which vibrator usage is checked
+ *
+ * This function allocates vibrator.
+ * Mask is added here as audioio driver controls left and right vibrator
+ * separately (can work independently). In case when audioio has allocated
+ * one of its channels (left or right) it should be still able to allocate
+ * the other channel.
+ *
+ * Returns:
+ * 0 - Success
+ * -EBUSY - other client already registered
+ **/
+int ste_audioio_vibrator_alloc(int client, int mask)
+{
+ int error = 0;
+
+ /* Check if other client is already using vibrator */
+ if (ptr_audio_codec_cnxt->vibra_client & ~mask)
+ error = -EBUSY;
+ else
+ ptr_audio_codec_cnxt->vibra_client |= client;
+
+ return error;
+}
+
+/**
+ * ste_audioio_vibrator_release()
+ * @client: Client id which releases vibrator
+ *
+ * This function releases vibrator
+ **/
+void ste_audioio_vibrator_release(int client)
+{
+ ptr_audio_codec_cnxt->vibra_client &= ~client;
+}
+
+/**
+ * ste_audioio_vibrator_pwm_control()
+ * @client: Client id which will use vibrator
+ * @left_speed: Left vibrator speed
+ * @right_speed: Right vibrator speed
+ *
+ * This function controls vibrator using PWM source
+ *
+ * Returns:
+ * 0 - success
+ * -EBUSY - Vibrator already used
+ **/
+int ste_audioio_vibrator_pwm_control(
+ int client,
+ struct ste_vibra_speed left_speed,
+ struct ste_vibra_speed right_speed)
+{
+ int error = 0;
+
+ mutex_lock(&ptr_audio_codec_cnxt->audio_io_mutex);
+
+ /* Try to allocate vibrator for given client */
+ error = ste_audioio_vibrator_alloc(client, client);
+
+ mutex_unlock(&ptr_audio_codec_cnxt->audio_io_mutex);
+
+ if (error)
+ return error;
+
+ /* Duty cycle supported by vibrator's PWM is 0-100 */
+ if (left_speed.positive > STE_AUDIOIO_VIBRATOR_MAX_SPEED)
+ left_speed.positive = STE_AUDIOIO_VIBRATOR_MAX_SPEED;
+
+ if (right_speed.positive > STE_AUDIOIO_VIBRATOR_MAX_SPEED)
+ right_speed.positive = STE_AUDIOIO_VIBRATOR_MAX_SPEED;
+
+ if (left_speed.negative > STE_AUDIOIO_VIBRATOR_MAX_SPEED)
+ left_speed.negative = STE_AUDIOIO_VIBRATOR_MAX_SPEED;
+
+ if (right_speed.negative > STE_AUDIOIO_VIBRATOR_MAX_SPEED)
+ right_speed.negative = STE_AUDIOIO_VIBRATOR_MAX_SPEED;
+
+ if (left_speed.negative || right_speed.negative ||
+ left_speed.positive || right_speed.positive) {
+ /* Power up audio block for vibrator */
+ error = ste_audio_io_core_api_powerup_audiocodec(
+ STE_AUDIOIO_POWER_VIBRA);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Audio power up failed %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ (EN_VIBL_MASK|EN_VIBR_MASK), 0);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Powerup Vibrator Class-D driver %d",
+ error);
+ return error;
+ }
+
+ error = HW_REG_WRITE(VIB_DRIVER_CONF_REG, 0xff);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Enable Vibrator PWM generator %d",
+ error);
+ return error;
+ }
+ }
+
+ error = HW_REG_WRITE(PWM_VIBNL_CONF_REG, left_speed.negative);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Write Left Vibrator negative PWM %d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_REG_WRITE(PWM_VIBPL_CONF_REG, left_speed.positive);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Write Left Vibrator positive PWM %d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_REG_WRITE(PWM_VIBNR_CONF_REG, right_speed.negative);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Write Right Vibrator negative PWM %d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_REG_WRITE(PWM_VIBPR_CONF_REG, right_speed.positive);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Write Right Vibrator positive PWM %d", error);
+ goto err_cleanup;
+ }
+
+ if (!left_speed.negative && !right_speed.negative &&
+ !left_speed.positive && !right_speed.positive) {
+ error = HW_REG_WRITE(VIB_DRIVER_CONF_REG, 0);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Disable PWM Vibrator generator %d",
+ error);
+ goto err_cleanup;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ 0, (EN_VIBL_MASK|EN_VIBR_MASK));
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Power down Vibrator Class-D driver %d",
+ error);
+ goto err_cleanup;
+ }
+
+ /* Power down audio block */
+ error = ste_audio_io_core_api_powerdown_audiocodec(
+ STE_AUDIOIO_POWER_VIBRA);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "Audio power down failed %d", error);
+ goto err_cleanup;
+ }
+ }
+
+err_cleanup:
+ /* Release client */
+ if (!left_speed.negative && !right_speed.negative &&
+ !left_speed.positive && !right_speed.positive) {
+ mutex_lock(&ptr_audio_codec_cnxt->audio_io_mutex);
+ ste_audioio_vibrator_release(client);
+ mutex_unlock(&ptr_audio_codec_cnxt->audio_io_mutex);
+ }
+ return error;
+}
+EXPORT_SYMBOL(ste_audioio_vibrator_pwm_control);
+
+/**
+ * @brief This function sets FIR coefficients
+ * @fir_coeffs: pointer to structure audioio_fir_coefficients_t
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_core_api_fir_coeffs_control(struct audioio_fir_coefficients_t
+ *fir_coeffs)
+{
+ unsigned char coefficient;
+ int i, error;
+
+ if (fir_coeffs->start_addr >= STE_AUDIOIO_MAX_COEFFICIENTS)
+ return -EINVAL;
+
+ mutex_lock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+
+ error = HW_REG_WRITE(SIDETONE_FIR_ADDR_REG, fir_coeffs->start_addr);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "FIR start address write failed %d", error);
+ goto err_cleanup;
+ }
+
+ for (i = fir_coeffs->start_addr;
+ i < STE_AUDIOIO_MAX_COEFFICIENTS; i++) {
+
+ coefficient = (fir_coeffs->coefficients[i]>>8) & 0xff;
+ error = HW_REG_WRITE(SIDETONE_FIR_COEFF_MSB_REG, coefficient);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "FIR coefficient [%d] msb write failed %d", i, error);
+ goto err_cleanup;
+ }
+
+ coefficient = fir_coeffs->coefficients[i] & 0xff;
+ error = HW_REG_WRITE(SIDETONE_FIR_COEFF_LSB_REG, coefficient);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "FIR coefficient [%d] lsb write failed %d", i, error);
+ goto err_cleanup;
+ }
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SIDETONE_FIR_ADDR_REG,
+ APPLY_FIR_COEFFS_MASK, 0);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "FIR coefficients activation failed %d", error);
+ goto err_cleanup;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(FILTERS_CONTROL_REG,
+ FIR_FILTERCONTROL, 0);
+ if (error) {
+ dev_err(ptr_audio_codec_cnxt->dev,
+ "ST FIR Filters enable failed %d", error);
+ goto err_cleanup;
+ }
+
+err_cleanup:
+ mutex_unlock(&(ptr_audio_codec_cnxt->audio_io_mutex));
+ return error;
+}
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_core.h b/drivers/misc/audio_io_dev/ste_audio_io_core.h
new file mode 100644
index 00000000000..7d109eb9e83
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_core.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#ifndef _AUDIOIO_CORE_H_
+#define _AUDIOIO_CORE_H_
+
+#include <mach/ste_audio_io_ioctl.h>
+#include "ste_audio_io_func.h"
+#include "ste_audio_io_hwctrl_common.h"
+
+#define MAX_NO_CHANNELS 4
+
+#define STE_AUDIOIO_POWER_AUDIO 1
+#define STE_AUDIOIO_POWER_VIBRA 2
+
+struct transducer_context_t {
+ /* public variables */
+ int gain[MAX_NO_CHANNELS];
+ int is_muted[MAX_NO_CHANNELS];
+ int is_power_up[MAX_NO_CHANNELS];
+ /* public funcs */
+ int (*pwr_up_func)(enum AUDIOIO_CH_INDEX, struct device *);
+ int (*pwr_down_func)(enum AUDIOIO_CH_INDEX, struct device *);
+ int (*pwr_state_func)(struct device *);
+ int (*set_gain_func)(enum AUDIOIO_CH_INDEX, u16, int, u32,
+ struct device *);
+ int (*get_gain_func)(int *, int *, u16, struct device *);
+ int (*mute_func)(enum AUDIOIO_CH_INDEX, struct device *);
+ int (*unmute_func)(enum AUDIOIO_CH_INDEX, int *, struct device *);
+ int (*mute_state_func)(struct device *);
+ int (*enable_fade_func)(struct device *);
+ int (*disable_fade_func)(struct device *);
+ int (*switch_to_burst_func)(int, struct device *);
+ int (*switch_to_normal_func)(struct device *);
+ int (*enable_loop)(enum AUDIOIO_CH_INDEX, enum AUDIOIO_HAL_HW_LOOPS,
+ int, struct device *, void *);
+ int (*disable_loop)(enum AUDIOIO_CH_INDEX, enum AUDIOIO_HAL_HW_LOOPS,
+ struct device *, void *);
+};
+
+struct audiocodec_context_t {
+ int audio_codec_powerup;
+ int power_client;
+ int vibra_client;
+ struct mutex audio_io_mutex;
+ struct mutex vibrator_mutex;
+ struct transducer_context_t *transducer[MAX_NO_TRANSDUCERS];
+ struct device *dev;
+ int (*gpio_altf_init) (void);
+ int (*gpio_altf_exit) (void);
+};
+
+
+int ste_audio_io_core_api_access_read(struct audioio_data_t *dev_data);
+
+int ste_audio_io_core_api_access_write(struct audioio_data_t *dev_data);
+
+int ste_audio_io_core_api_power_control_transducer(
+ struct audioio_pwr_ctrl_t *pwr_ctrl);
+
+int ste_audio_io_core_api_power_status_transducer(
+ struct audioio_pwr_ctrl_t *pwr_ctrl);
+
+int ste_audio_io_core_api_loop_control(struct audioio_loop_ctrl_t *loop_ctrl);
+
+int ste_audio_io_core_api_loop_status(struct audioio_loop_ctrl_t *loop_ctrl);
+
+int ste_audio_io_core_api_get_transducer_gain_capability(
+ struct audioio_get_gain_t *get_gain);
+
+int ste_audio_io_core_api_gain_capabilities_loop(
+ struct audioio_gain_loop_t *gain_loop);
+
+int ste_audio_io_core_api_supported_loops(
+ struct audioio_support_loop_t *support_loop);
+
+int ste_audio_io_core_api_gain_descriptor_transducer(
+ struct audioio_gain_desc_trnsdr_t *gdesc_trnsdr);
+
+int ste_audio_io_core_api_gain_control_transducer(
+ struct audioio_gain_ctrl_trnsdr_t *gctrl_trnsdr);
+
+int ste_audio_io_core_api_gain_query_transducer(
+ struct audioio_gain_ctrl_trnsdr_t *gctrl_trnsdr);
+
+int ste_audio_io_core_api_mute_control_transducer(
+ struct audioio_mute_trnsdr_t *mute_trnsdr);
+
+int ste_audio_io_core_api_mute_status_transducer(
+ struct audioio_mute_trnsdr_t *mute_trnsdr);
+
+int ste_audio_io_core_api_fading_control(struct audioio_fade_ctrl_t *fade_ctrl);
+
+int ste_audio_io_core_api_burstmode_control(
+ struct audioio_burst_ctrl_t *burst_ctrl);
+
+int ste_audio_io_core_api_powerup_audiocodec(int power_client);
+
+int ste_audio_io_core_api_powerdown_audiocodec(int power_client);
+
+int ste_audio_io_core_api_init_data(struct platform_device *pdev);
+
+bool ste_audio_io_core_is_ready_for_suspend(void);
+void ste_audio_io_core_api_free_data(void);
+
+int ste_audio_io_core_api_fsbitclk_control(
+ struct audioio_fsbitclk_ctrl_t *fsbitclk_ctrl);
+int ste_audio_io_core_api_pseudoburst_control(
+ struct audioio_pseudoburst_ctrl_t *pseudoburst_ctrl);
+
+void ste_audio_io_core_api_store_data(enum AUDIOIO_CH_INDEX channel_index,
+ int *ptr, int value);
+
+int ste_audioio_vibrator_alloc(int client, int mask);
+
+void ste_audioio_vibrator_release(int client);
+
+enum AUDIOIO_COMMON_SWITCH ste_audio_io_core_api_get_status(
+ enum AUDIOIO_CH_INDEX channel_index, int *ptr);
+
+int ste_audio_io_core_api_acodec_power_control(struct audioio_acodec_pwr_ctrl_t
+ *audio_acodec_pwr_ctrl);
+
+int ste_audio_io_core_api_fir_coeffs_control(struct audioio_fir_coefficients_t
+ *fir_coeffs);
+
+int ste_audio_io_core_debug(int x);
+
+#endif /* _AUDIOIO_CORE_H_ */
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_dev.c b/drivers/misc/audio_io_dev/ste_audio_io_dev.c
new file mode 100644
index 00000000000..8b677909104
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_dev.c
@@ -0,0 +1,738 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include "ste_audio_io_dev.h"
+
+#define STR_DEBUG_ON "debug on"
+#define AUDIOIO_DEVNAME "ab8500-codec"
+
+static int ste_audio_io_open(struct inode *inode, struct file *filp);
+static int ste_audio_io_release(struct inode *inode, struct file *filp);
+static long ste_audio_io_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
+static int ste_audio_io_cmd_parser(unsigned int cmd, unsigned long arg);
+static ssize_t ste_audio_io_write(struct file *filp,
+ const char __user *buf, size_t count, loff_t *f_pos);
+
+
+/**
+ * @brief Check IOCTL type, command no and access direction
+ * @ inode value corresponding to the file descriptor
+ * @file value corresponding to the file descriptor
+ * @cmd IOCTL command code
+ * @arg Command argument
+ * @return 0 on success otherwise negative error code
+ */
+static long ste_audio_io_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int retval = 0;
+ int err = 0;
+
+ /* Check type and command number */
+ if (_IOC_TYPE(cmd) != AUDIOIO_IOC_MAGIC)
+ return -ENOTTY;
+
+ /* IOC_DIR is from the user perspective, while access_ok is
+ * from the kernel perspective; so they look reversed.
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, (void __user *)arg,
+ _IOC_SIZE(cmd));
+ if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, (void __user *)arg,
+ _IOC_SIZE(cmd));
+ if (err)
+ return -EFAULT;
+
+ retval = ste_audio_io_cmd_parser(cmd, arg);
+
+ return retval;
+}
+/**
+ * @brief IOCTL call to read the value from AB8500 device
+ * @cmd IOCTL command code
+ * @arg Command argument
+ * @return 0 on success otherwise negative error code
+ */
+
+static int process_read_register_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_data_t *audio_dev_data;
+
+ audio_dev_data = (struct audioio_data_t *)&cmd_data;
+
+ if (copy_from_user(audio_dev_data, (void __user *)arg,
+ sizeof(struct audioio_data_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_access_read(audio_dev_data);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_dev_data,
+ sizeof(struct audioio_data_t)))
+ return -EFAULT;
+ return 0;
+}
+/**
+ * @brief IOCTL call to write the given value to the AB8500 device
+ * @cmd IOCTL command code
+ * @arg Command argument
+ * @return 0 on success otherwise negative error code
+ */
+
+static int process_write_register_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_data_t *audio_dev_data;
+
+ audio_dev_data = (struct audioio_data_t *)&cmd_data;
+
+ if (copy_from_user(audio_dev_data, (void __user *)arg,
+ sizeof(struct audioio_data_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_access_write(audio_dev_data);
+
+ return retval;
+}
+/**
+ * @brief IOCTL call to control the power on/off of hardware components
+ * @cmd IOCTL command code
+ * @arg Command argument
+ * @return 0 on success otherwise negative error code
+ */
+
+static int process_pwr_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_pwr_ctrl_t *audio_pwr_ctrl;
+
+ audio_pwr_ctrl = (struct audioio_pwr_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_pwr_ctrl, (void __user *)arg,
+ sizeof(struct audioio_pwr_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_power_control_transducer(audio_pwr_ctrl);
+
+ return retval;
+}
+
+static int process_pwr_sts_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_pwr_ctrl_t *audio_pwr_sts;
+
+ audio_pwr_sts = (struct audioio_pwr_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_pwr_sts, (void __user *)arg,
+ sizeof(struct audioio_pwr_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_power_status_transducer(audio_pwr_sts);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_pwr_sts,
+ sizeof(struct audioio_pwr_ctrl_t)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int process_lp_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_loop_ctrl_t *audio_lp_ctrl;
+
+ audio_lp_ctrl = (struct audioio_loop_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_lp_ctrl, (void __user *)arg,
+ sizeof(struct audioio_loop_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_loop_control(audio_lp_ctrl);
+
+ return retval;
+}
+
+static int process_lp_sts_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_loop_ctrl_t *audio_lp_sts;
+
+ audio_lp_sts = (struct audioio_loop_ctrl_t *)&cmd_data;
+
+
+ if (copy_from_user(audio_lp_sts, (void __user *)arg,
+ sizeof(struct audioio_loop_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_loop_status(audio_lp_sts);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_lp_sts,
+ sizeof(struct audioio_loop_ctrl_t)))
+ return -EFAULT;
+ return 0;
+}
+
+static int process_get_trnsdr_gain_capability_cmd(unsigned int cmd,
+ unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_get_gain_t *audio_trnsdr_gain;
+
+ audio_trnsdr_gain = (struct audioio_get_gain_t *)&cmd_data;
+
+ if (copy_from_user(audio_trnsdr_gain, (void __user *)arg,
+ sizeof(struct audioio_get_gain_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_get_transducer_gain_capability(
+ audio_trnsdr_gain);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_trnsdr_gain,
+ sizeof(struct audioio_get_gain_t)))
+ return -EFAULT;
+ return 0;
+}
+
+static int process_gain_cap_loop_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_gain_loop_t *audio_gain_loop;
+
+ audio_gain_loop = (struct audioio_gain_loop_t *)&cmd_data;
+
+ if (copy_from_user(audio_gain_loop, (void __user *)arg,
+ sizeof(struct audioio_gain_loop_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_gain_capabilities_loop(audio_gain_loop);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_gain_loop,
+ sizeof(struct audioio_gain_loop_t)))
+ return -EFAULT;
+ return 0;
+}
+
+
+static int process_support_loop_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_support_loop_t *audio_spprt_loop;
+
+ audio_spprt_loop = (struct audioio_support_loop_t *)&cmd_data;
+
+ if (copy_from_user(audio_spprt_loop, (void __user *)arg,
+ sizeof(struct audioio_support_loop_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_supported_loops(audio_spprt_loop);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_spprt_loop,
+ sizeof(struct audioio_support_loop_t)))
+ return -EFAULT;
+ return 0;
+}
+
+
+static int process_gain_desc_trnsdr_cmd(unsigned int cmd, unsigned long arg)
+
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_gain_desc_trnsdr_t *audio_gain_desc;
+
+ audio_gain_desc = (struct audioio_gain_desc_trnsdr_t *)&cmd_data;
+
+ if (copy_from_user(audio_gain_desc, (void __user *)arg,
+ sizeof(struct audioio_gain_desc_trnsdr_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_gain_descriptor_transducer(
+ audio_gain_desc);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_gain_desc,
+ sizeof(struct audioio_gain_desc_trnsdr_t)))
+ return -EFAULT;
+ return 0;
+}
+
+
+static int process_gain_ctrl_trnsdr_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_gain_ctrl_trnsdr_t *audio_gain_ctrl;
+
+ audio_gain_ctrl = (struct audioio_gain_ctrl_trnsdr_t *)&cmd_data;
+
+ if (copy_from_user(audio_gain_ctrl, (void __user *)arg,
+ sizeof(struct audioio_gain_ctrl_trnsdr_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_gain_control_transducer(
+ audio_gain_ctrl);
+
+ return retval;
+}
+
+static int process_gain_query_trnsdr_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_gain_ctrl_trnsdr_t *audio_gain_query;
+
+ audio_gain_query = (struct audioio_gain_ctrl_trnsdr_t *)&cmd_data;
+
+ if (copy_from_user(audio_gain_query, (void __user *)arg,
+ sizeof(struct audioio_gain_ctrl_trnsdr_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_gain_query_transducer(audio_gain_query);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_gain_query,
+ sizeof(struct audioio_gain_ctrl_trnsdr_t)))
+ return -EFAULT;
+ return 0;
+}
+
+static int process_mute_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_mute_trnsdr_t *audio_mute_ctrl;
+
+ audio_mute_ctrl = (struct audioio_mute_trnsdr_t *)&cmd_data;
+ if (copy_from_user(audio_mute_ctrl , (void __user *)arg,
+ sizeof(struct audioio_mute_trnsdr_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_mute_control_transducer(
+ audio_mute_ctrl);
+
+ return retval;
+}
+
+static int process_mute_sts_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_mute_trnsdr_t *audio_mute_sts;
+
+ audio_mute_sts = (struct audioio_mute_trnsdr_t *)&cmd_data;
+
+ if (copy_from_user(audio_mute_sts, (void __user *)arg,
+ sizeof(struct audioio_mute_trnsdr_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_mute_status_transducer(audio_mute_sts);
+ if (0 != retval)
+ return retval;
+
+ if (copy_to_user((void __user *)arg, audio_mute_sts,
+ sizeof(struct audioio_mute_trnsdr_t)))
+ return -EFAULT;
+ return 0;
+}
+
+static int process_fade_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_fade_ctrl_t *audio_fade;
+ audio_fade = (struct audioio_fade_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_fade , (void __user *)arg,
+ sizeof(struct audioio_fade_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_fading_control(audio_fade);
+
+ return retval;
+}
+
+static int process_burst_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_burst_ctrl_t *audio_burst;
+
+ audio_burst = (struct audioio_burst_ctrl_t *)&cmd_data;
+ if (copy_from_user(audio_burst , (void __user *)arg,
+ sizeof(struct audioio_burst_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_burstmode_control(audio_burst);
+
+ return retval;
+
+ return 0;
+}
+
+static int process_fsbitclk_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_fsbitclk_ctrl_t *audio_fsbitclk;
+
+ audio_fsbitclk = (struct audioio_fsbitclk_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_fsbitclk , (void __user *)arg,
+ sizeof(struct audioio_fsbitclk_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_fsbitclk_control(audio_fsbitclk);
+
+ return retval;
+
+ return 0;
+
+}
+
+static int process_pseudoburst_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_pseudoburst_ctrl_t *audio_pseudoburst;
+
+ audio_pseudoburst = (struct audioio_pseudoburst_ctrl_t *)&cmd_data;
+
+ if (copy_from_user(audio_pseudoburst , (void __user *)arg,
+ sizeof(struct audioio_pseudoburst_ctrl_t)))
+ return -EFAULT;
+
+ retval = ste_audio_io_core_api_pseudoburst_control(audio_pseudoburst);
+
+ return retval;
+
+ return 0;
+
+}
+static int process_audiocodec_pwr_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ union audioio_cmd_data_t cmd_data;
+ struct audioio_acodec_pwr_ctrl_t *audio_acodec_pwr_ctrl;
+ audio_acodec_pwr_ctrl = (struct audioio_acodec_pwr_ctrl_t *)&cmd_data;
+ if (copy_from_user(audio_acodec_pwr_ctrl, (void __user *)arg,
+ sizeof(struct audioio_acodec_pwr_ctrl_t)))
+ return -EFAULT;
+ retval = ste_audio_io_core_api_acodec_power_control(
+ audio_acodec_pwr_ctrl);
+ return retval;
+}
+
+static int process_fir_coeffs_ctrl_cmd(unsigned int cmd, unsigned long arg)
+{
+ int retval;
+ struct audioio_fir_coefficients_t *cmd_data;
+ cmd_data = kmalloc(sizeof(struct audioio_fir_coefficients_t),
+ GFP_KERNEL);
+ if (!cmd_data)
+ return -ENOMEM;
+ if (copy_from_user(cmd_data, (void __user *)arg,
+ sizeof(struct audioio_fir_coefficients_t))) {
+ kfree(cmd_data);
+ return -EFAULT;
+ }
+ retval = ste_audio_io_core_api_fir_coeffs_control(cmd_data);
+ kfree(cmd_data);
+ return retval;
+}
+
+static int ste_audio_io_cmd_parser(unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+
+ switch (cmd) {
+ case AUDIOIO_READ_REGISTER:
+ retval = process_read_register_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_WRITE_REGISTER:
+ retval = process_write_register_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_PWR_CTRL_TRNSDR:
+ retval = process_pwr_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_PWR_STS_TRNSDR:
+ retval = process_pwr_sts_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_LOOP_CTRL:
+ retval = process_lp_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_LOOP_STS:
+ retval = process_lp_sts_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_GET_TRNSDR_GAIN_CAPABILITY:
+ retval = process_get_trnsdr_gain_capability_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_GAIN_CAP_LOOP:
+ retval = process_gain_cap_loop_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_SUPPORT_LOOP:
+ retval = process_support_loop_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_GAIN_DESC_TRNSDR:
+ retval = process_gain_desc_trnsdr_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_GAIN_CTRL_TRNSDR:
+ retval = process_gain_ctrl_trnsdr_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_GAIN_QUERY_TRNSDR:
+ retval = process_gain_query_trnsdr_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_MUTE_CTRL_TRNSDR:
+ retval = process_mute_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_MUTE_STS_TRNSDR:
+ retval = process_mute_sts_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_FADE_CTRL:
+ retval = process_fade_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_BURST_CTRL:
+ retval = process_burst_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_FSBITCLK_CTRL:
+ retval = process_fsbitclk_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_PSEUDOBURST_CTRL:
+ retval = process_pseudoburst_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_AUDIOCODEC_PWR_CTRL:
+ retval = process_audiocodec_pwr_ctrl_cmd(cmd, arg);
+ break;
+
+ case AUDIOIO_FIR_COEFFS_CTRL:
+ retval = process_fir_coeffs_ctrl_cmd(cmd, arg);
+ break;
+ }
+ return retval;
+}
+
+static int ste_audio_io_open(struct inode *inode, struct file *filp)
+{
+ if (!try_module_get(THIS_MODULE))
+ return -ENODEV;
+ return 0;
+}
+
+static int ste_audio_io_release(struct inode *inode, struct file *filp)
+{
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static ssize_t ste_audio_io_write(struct file *filp,
+ const char __user *buf, size_t count, loff_t *f_pos)
+{
+ char *x = kmalloc(count, GFP_KERNEL);
+ int debug_flag = 0;
+
+ if (copy_from_user(x, buf, count))
+ return -EFAULT;
+
+ if (count >= strlen(STR_DEBUG_ON)) {
+
+ if (!strncmp(STR_DEBUG_ON, x, strlen(STR_DEBUG_ON)))
+ debug_flag = 1;
+ else
+ debug_flag = 0;
+ }
+
+ ste_audio_io_core_debug(debug_flag);
+
+ kfree(x);
+
+ return count;
+}
+
+static const struct file_operations ste_audio_io_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = ste_audio_io_ioctl,
+ .open = ste_audio_io_open,
+ .release = ste_audio_io_release,
+ .write = ste_audio_io_write,
+};
+
+/**
+ * audio_io_misc_dev - Misc device config for audio_io
+ */
+static struct miscdevice audio_io_misc_dev = {
+ MISC_DYNAMIC_MINOR,
+ "audioio",
+ &ste_audio_io_fops
+};
+
+/**
+ * ste_audio_io_probe() - probe the device
+ * @pdev: pointer to the platform device structure
+ *
+ * This funtion is called after the driver is registered to platform
+ * device framework. It does allocate the memory for the internal
+ * data structure and intialized core APIs.
+ */
+static int ste_audio_io_drv_probe(struct platform_device *pdev)
+{
+ int error;
+
+ ste_audio_io_device = pdev;
+
+ dev_dbg(&ste_audio_io_device->dev, "ste_audio_io device probe\n");
+
+ error = misc_register(&audio_io_misc_dev);
+ if (error) {
+ printk(KERN_WARNING "%s: registering misc device failed\n",
+ __func__);
+ return error;
+ }
+
+ error = ste_audio_io_core_api_init_data(ste_audio_io_device);
+ if (error < 0) {
+ dev_err(&ste_audio_io_device->dev,
+ "ste_audioio_core_api_init_data failed err = %d",
+ error);
+ goto ste_audio_io_misc_deregister;
+ }
+ return 0;
+
+ste_audio_io_misc_deregister:
+ misc_deregister(&audio_io_misc_dev);
+ return error;
+}
+
+/**
+ * ste_audio_io_remove() - Removes the device
+ * @pdev: pointer to the platform_device structure
+ *
+ * This function is called when this mnodule is removed using rmmod
+ */
+static int ste_audio_io_drv_remove(struct platform_device *pdev)
+{
+ ste_audio_io_core_api_free_data();
+ misc_deregister(&audio_io_misc_dev);
+ return 0;
+}
+
+/**
+ * ste_audio_io_drv_suspend - suspend audio_io
+ * @pdev: platform data
+ * @state: power down level
+ */
+static int ste_audio_io_drv_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ if (ste_audio_io_core_is_ready_for_suspend())
+ return 0;
+ else
+ return -EINVAL;
+}
+
+/**
+ * ste_audio_io_drv_resume - put back audio_io in the normal state
+ * @pdev: platform data
+ */
+static int ste_audio_io_drv_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+/**
+ * struct audio_io_driver: audio_io platform structure
+ * @probe: The probe funtion to be called
+ * @remove: The remove funtion to be called
+ * @resume: The resume function to be called
+ * @suspend: The suspend function to be called
+ * @driver: The driver data
+ */
+static struct platform_driver ste_audio_io_driver = {
+ .probe = ste_audio_io_drv_probe,
+ .remove = ste_audio_io_drv_remove,
+ .driver = {
+ .name = AUDIOIO_DEVNAME,
+ .owner = THIS_MODULE,
+ },
+ .suspend = ste_audio_io_drv_suspend,
+ .resume = ste_audio_io_drv_resume,
+};
+
+/** Pointer to platform device needed to access abx500 core functions */
+struct platform_device *ste_audio_io_device;
+
+static int __init ste_audio_io_init(void)
+{
+ return platform_driver_register(&ste_audio_io_driver);
+}
+module_init(ste_audio_io_init);
+
+static void __exit ste_audio_io_exit(void)
+{
+ platform_driver_unregister(&ste_audio_io_driver);
+}
+module_exit(ste_audio_io_exit);
+
+MODULE_AUTHOR("Deepak KARDA <deepak.karda@stericsson.com>");
+MODULE_DESCRIPTION("STE_AUDIO_IO");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_dev.h b/drivers/misc/audio_io_dev/ste_audio_io_dev.h
new file mode 100644
index 00000000000..bcb9dce3ad2
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_dev.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#ifndef _AUDIOIO_DEV_H_
+#define _AUDIOIO_DEV_H_
+
+#include <mach/ste_audio_io_ioctl.h>
+#include "ste_audio_io_core.h"
+
+union audioio_cmd_data_t {
+ struct audioio_burst_ctrl_t audioio_burst_ctrl;
+ struct audioio_fade_ctrl_t audioio_fade_ctrl;
+ struct audioio_mute_trnsdr_t audioio_mute_trnsdr;
+ struct audioio_gain_ctrl_trnsdr_t audioio_gain_ctrl_trnsdr;
+ struct audioio_gain_desc_trnsdr_t audioio_gain_desc_trnsdr;
+ struct audioio_support_loop_t audioio_support_loop;
+ struct audioio_gain_loop_t audioio_gain_loop;
+ struct audioio_get_gain_t audioio_get_gain;
+ struct audioio_loop_ctrl_t audioio_loop_ctrl;
+ struct audioio_pwr_ctrl_t audioio_pwr_ctrl;
+ struct audioio_data_t audioio_data;
+ struct audioio_fsbitclk_ctrl_t audioio_fsbitclk_ctrl;
+ struct audioio_acodec_pwr_ctrl_t audioio_acodec_pwr_ctrl;
+ struct audioio_pseudoburst_ctrl_t audioio_pseudoburst_ctrl;
+};
+
+
+#endif /* _AUDIOIO_DEV_H_ */
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_func.c b/drivers/misc/audio_io_dev/ste_audio_io_func.c
new file mode 100644
index 00000000000..7238085938e
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_func.c
@@ -0,0 +1,4371 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <mach/ste_audio_io_vibrator.h>
+#include <mach/ste_audio.h>
+#include "ste_audio_io_func.h"
+#include "ste_audio_io_core.h"
+#include "ste_audio_io_ab8500_reg_defs.h"
+#include "ste_audio_io_hwctrl_common.h"
+
+static struct clk *clk_ptr_msp0;
+static int bluetooth_power_up_count;
+static int acodec_reg_dump;
+
+#define NCP_TIMEOUT 200 /* 200 ms */
+/*
+ * TODO: Use proper register defines instead of home-made generic ones.
+ */
+#define SHIFT_QUARTET0 0
+#define SHIFT_QUARTET1 4
+#define MASK_QUARTET (0xFUL)
+#define MASK_QUARTET1 (MASK_QUARTET << SHIFT_QUARTET1)
+#define MASK_QUARTET0 (MASK_QUARTET << SHIFT_QUARTET0)
+
+/**
+ * @brief Modify the specified register
+ * @reg Register
+ * @mask_set Bit to be set
+ * @mask_clear Bit to be cleared
+ * @return 0 on success otherwise negative error code
+ */
+
+unsigned int ab8500_acodec_modify_write(unsigned int reg, u8 mask_set,
+ u8 mask_clear)
+{
+ u8 value8, retval = 0;
+ value8 = HW_REG_READ(reg);
+ /* clear the specified bit */
+ value8 &= ~mask_clear;
+ /* set the asked bit */
+ value8 |= mask_set;
+ retval = HW_REG_WRITE(reg, value8);
+ return retval;
+}
+
+/**
+ * @brief Power up headset on a specific channel
+ * @channel_index Channel-index of headset
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_headset(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+ unsigned long end_time;
+
+ /* Check if HS PowerUp request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "HS should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ ste_audio_io_mute_headset(channel_index, dev);
+
+ error = HW_ACODEC_MODIFY_WRITE(NCP_ENABLE_HS_AUTOSTART_REG,
+ HS_AUTO_EN, 0);
+ if (0 != error) {
+ dev_err(dev, "NCP fully controlled with EnCpHs bit %d", error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(NCP_ENABLE_HS_AUTOSTART_REG,
+ (EN_NEG_CP|HS_AUTO_EN), 0);
+ if (0 != error) {
+ dev_err(dev, "Enable Negative Charge Pump %d", error);
+ return error;
+ }
+
+ /* Wait for negative charge pump to start */
+ end_time = jiffies + msecs_to_jiffies(NCP_TIMEOUT);
+ while (!(HW_REG_READ(IRQ_STATUS_MSB_REG) & NCP_READY_MASK)
+ && time_after_eq(end_time, jiffies)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+
+ if (!(HW_REG_READ(IRQ_STATUS_MSB_REG) & NCP_READY_MASK)) {
+ error = -EFAULT;
+ dev_err(dev, "Negative Charge Pump start error % d", error);
+ return error;
+ }
+
+ /* Enable DA1 for HSL */
+ if (channel_index & e_CHANNEL_1) {
+
+ /* Power Up HSL driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ EN_HSL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HSL Driver %d", error);
+ return error;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ if (EN_DA1 & initialVal_DA)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA1_REG,
+ SLOT08_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA1 from Slot 08 %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ DA1_TO_HSL, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "DA_IN1 path mixed with sidetone FIR %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA1, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up HSL %d ", error);
+ return error;
+ }
+
+ /* Power Up HSL DAC driver */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG,
+ POWER_UP_HSL_DAC, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HSL DAC driver %d", error);
+ return error;
+ }
+
+ /* Power up HSL DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_HSL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up HSL DAC and digital path %d",
+ error);
+ return error;
+ }
+
+ /*
+ * Disable short detection. Pull Down output to ground,
+ * Use local oscillator, Gain change without zero cross control
+ */
+ error = HW_ACODEC_MODIFY_WRITE(SHORT_CIRCUIT_DISABLE_REG,
+ HS_SHORT_DIS|HS_PULL_DOWN_EN|HS_OSC_EN|HS_ZCD_DIS, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable short detection."
+ "Pull Down output to ground,Use local oscillator,Gain"
+ "change without zero cross control %d", error);
+ return error;
+ }
+ }
+
+ /* Enable DA2 for HSR */
+ if (channel_index & e_CHANNEL_2) {
+
+ /* Power Up HSR driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ EN_HSR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HSR Driver %d", error);
+ return error;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (EN_DA2 & initialVal_DA)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA2_REG,
+ SLOT09_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA2 from Slot 09 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, DA2_TO_HSR,
+ 0);
+ if (0 != error) {
+ dev_err(dev,
+ "DA_IN2 path mixed with sidetone FIR %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA2, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up HSR %d ", error);
+ return error;
+ }
+
+ /* Power Up HSR DAC driver */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG,
+ POWER_UP_HSR_DAC, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HSR DAC driver %d", error);
+ return error;
+ }
+
+ /* Power up HSR DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_HSR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up HSR DAC and digital path %d",
+ error);
+ return error;
+ }
+
+ /*
+ * TEST START .havent cleared the bits in power down.Disable short
+ * detection. Pull Down output to ground, Use local oscillator,
+ * Gain change without zero cross control
+ */
+
+ error = HW_ACODEC_MODIFY_WRITE(SHORT_CIRCUIT_DISABLE_REG,
+ HS_SHORT_DIS|HS_PULL_DOWN_EN|HS_OSC_EN|HS_ZCD_DIS, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable short detection."
+ "Pull Down output to ground, Use local oscillator,"
+ "Gain change without zero cross control %d", error);
+ return error;
+ }
+ /* TEST END */
+ }
+ ste_audio_io_unmute_headset(channel_index, 0, dev);
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+/**
+ * @brief Power down headset on a specific channel
+ * @channel_index Channel-index of headset
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_headset(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+ unsigned long end_time;
+
+ /* Check if HS Power Down request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "HS should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ /* Disable Negative Charge Pump */
+ error = HW_ACODEC_MODIFY_WRITE(NCP_ENABLE_HS_AUTOSTART_REG,
+ (EN_NEG_CP|HS_AUTO_EN), 0);
+ if (0 != error) {
+ dev_err(dev, "NCP not fully controlled with EnCpHs bit %d",
+ error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(NCP_ENABLE_HS_AUTOSTART_REG, 0,
+ EN_NEG_CP);
+ if (0 != error) {
+ dev_err(dev, "Disable Negative Charge Pump %d", error);
+ return error;
+ }
+
+ /* Wait for negative charge pump to stop */
+ end_time = jiffies + msecs_to_jiffies(NCP_TIMEOUT);
+ while ((HW_REG_READ(IRQ_STATUS_MSB_REG) & NCP_READY_MASK)
+ && time_after_eq(end_time, jiffies)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+
+ if (HW_REG_READ(IRQ_STATUS_MSB_REG) & NCP_READY_MASK) {
+ error = -EFAULT;
+ dev_err(dev, "Negative Charge Pump stop error % d", error);
+ return error;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_DA & EN_DA1))
+ return 0;
+
+ /* Power Down HSL driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG, 0,
+ EN_HSL_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power down HSL Driver %d", error);
+ return error;
+ }
+
+ /* Power Down HSL DAC driver */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ POWER_UP_HSL_DAC);
+ if (0 != error) {
+ dev_err(dev, "Power Up HSL DAC Driver %d", error);
+ return error;
+ }
+
+ /* Power Down HSL DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_HSL_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power down HSL DAC and digital path %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA1);
+ if (0 != error) {
+ dev_err(dev, "Disable DA1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ 0, DA1_TO_HSL);
+ if (0 != error) {
+ dev_err(dev,
+ "Clear DA_IN1 path mixed with sidetone FIR %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA1_REG, 0,
+ SLOT08_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA1 cleared from Slot 08 %d",
+ error);
+ return error;
+ }
+
+
+ }
+ /* Enable DA2 for HSR */
+
+ if (channel_index & e_CHANNEL_2) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_DA & EN_DA2))
+ return 0;
+
+ /* Power Down HSR driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG, 0,
+ EN_HSR_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power down HSR Driver %d", error);
+ return error;
+ }
+
+ /* Power Down HSR DAC driver */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ POWER_UP_HSR_DAC);
+ if (0 != error) {
+ dev_err(dev, "Power down HSR DAC Driver %d", error);
+ return error;
+ }
+
+ /* Power Down HSR DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_HSR_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power down HSR DAC and digital path %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA2);
+ if (0 != error) {
+ dev_err(dev, "Disable DA2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ DA2_TO_HSR);
+ if (0 != error) {
+ dev_err(dev,
+ "Clear DA_IN2 path mixed with sidetone FIR %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA2_REG, 0,
+ SLOT09_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA2 cleared from Slot 09 %d",
+ error);
+ return error;
+ }
+
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+/**
+ * @brief Mute headset on a specific channel
+ * @channel_index Headeset channel-index
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_mute_headset(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ /* Check if HS Mute request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "HS should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Mute HSL */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG,
+ EN_HSL_MASK | EN_HSL_DAC_MASK,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Mute HSL %d", error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* Mute HSR */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG,
+ EN_HSR_MASK | EN_HSR_DAC_MASK,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Mute HSR %d", error);
+ return error;
+ }
+ }
+
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+/**
+ * @brief Unmute headset on a specific channel
+ * @channel_index Headeset channel-index
+ * @gain Gain index of headset
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_unmute_headset(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+
+ /* Check if HS UnMute request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "HS should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ /* UnMute HSL */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG, 0,
+ EN_HSL_MASK | EN_HSL_DAC_MASK);
+ if (0 != error) {
+ dev_err(dev, "UnMute HSL %d", error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* UnMute HSR */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG, 0,
+ EN_HSR_MASK | EN_HSR_DAC_MASK);
+ if (0 != error) {
+ dev_err(dev, "UnMute HSR %d", error);
+ return error;
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+/**
+ * @brief Enables fading of headset on a specific channel
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_enable_fade_headset(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(SHORT_CIRCUIT_DISABLE_REG,
+ 0, DIS_HS_FAD);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for HS %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA1_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for HSL %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(HSL_EAR_DIGITAL_GAIN_REG, 0,
+ DIS_DIG_GAIN_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for Digital Gain of HSL %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA2_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for HSR %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(HSR_DIGITAL_GAIN_REG, 0,
+ DIS_DIG_GAIN_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for Digital Gain of HSR %d",
+ error);
+ return error;
+ }
+
+ return error;
+}
+/**
+ * @brief Disables fading of headset on a specific channel
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_disable_fade_headset(struct device *dev)
+{
+ int error = 0;
+ error = HW_ACODEC_MODIFY_WRITE(SHORT_CIRCUIT_DISABLE_REG,
+ DIS_HS_FAD, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for HS %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA1_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for HSL %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(HSL_EAR_DIGITAL_GAIN_REG,
+ DIS_DIG_GAIN_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for Digital Gain of HSL %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA2_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for HSR %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(HSR_DIGITAL_GAIN_REG,
+ DIS_DIG_GAIN_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for Digital Gain of HSR %d",
+ error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up earpiece
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_up_earpiece(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if Earpiece PowerUp request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "EARPIECE should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if Earpiece is already powered up or DA1 being used by HS */
+ if (EN_DA1 & initialVal_DA)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ DA1_TO_HSL, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "DA_IN1 path mixed with sidetone FIR %d", error);
+ return error;
+ }
+
+ /* Enable DA1 */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA1_REG,
+ SLOT08_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA1 from Slot 08 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA1, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DA1 %d", error);
+ return error;
+ }
+
+ /* Power Up EAR class-AB driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ EN_EAR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up EAR class-AB driver %d", error);
+ return error;
+ }
+
+ /* Power up EAR DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(
+ DIGITAL_OUTPUT_ENABLE_REG, EN_EAR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up EAR DAC and digital path %d", error);
+ return error;
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Power down earpiece
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_earpiece(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if Earpiece PowerDown request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "EARPIECE should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Check if Earpiece is already powered down or DA1 being used by HS */
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_DA & EN_DA1))
+ return 0;
+
+ /* Power Down EAR class-AB driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ 0, EN_EAR_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power Down EAR class-AB driver %d", error);
+ return error;
+ }
+
+ /* Power Down EAR DAC and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ 0, EN_EAR_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power Down EAR DAC and digital path %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0, DA1_TO_HSL);
+ if (0 != error) {
+ dev_err(dev,
+ "Clear DA_IN1 path mixed with sidetone FIR %d",
+ error);
+ return error;
+ }
+
+ /* Disable DA1 */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA1);
+ if (0 != error) {
+ dev_err(dev, "Disable DA1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA1_REG, 0,
+ SLOT08_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA1 cleared from Slot 08 %d", error);
+ return error;
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Mute earpiece
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_mute_earpiece(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+
+ /* Check if Earpiece Mute request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "EARPIECE should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Mute Earpiece */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG,
+ EN_EAR_MASK | EN_EAR_DAC_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Mute Earpiece %d", error);
+ return error;
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Unmute earpiece
+ * @channel_index Channel-index
+ * @gain Gain index of earpiece
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_unmute_earpiece(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+
+ /* Check if Earpiece UnMute request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "EARPIECE should have mono channel");
+ return -EINVAL;
+ }
+
+ /* UnMute Earpiece */
+ error = HW_ACODEC_MODIFY_WRITE(MUTE_HS_EAR_REG, 0,
+ EN_EAR_MASK | EN_EAR_DAC_MASK);
+ if (0 != error) {
+ dev_err(dev, "UnMute Earpiece %d", error);
+ return error;
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Enables fading of earpiece
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_enable_fade_earpiece(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA1_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for Ear %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(HSL_EAR_DIGITAL_GAIN_REG, 0,
+ DIS_DIG_GAIN_FADING);
+ if (0 != error) {
+ dev_err(dev,
+ "Enable fading for Digital Gain of Ear %d", error);
+ return error;
+ }
+
+ return error;
+}
+/**
+ * @brief Disables fading of earpiece
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_disable_fade_earpiece(struct device *dev)
+{
+ int error = 0;
+ error = HW_ACODEC_MODIFY_WRITE(DA1_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for Ear %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up IHF on a specific channel
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_ihf(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if IHF PowerUp request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "IHF should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (EN_DA3 & initialVal_DA)
+ return 0;
+
+ /* Enable DA3 for IHFL */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA3_REG,
+ SLOT10_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA3 from Slot 10 %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA3, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up IHFL %d", error);
+ return error;
+ }
+
+ /* Power Up HFL Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ EN_HFL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HFL Class-D Driver %d", error);
+ return error;
+ }
+
+ /* Power up HFL Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_HFL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up HFL Class D driver & digital path %d",
+ error);
+ return error;
+ }
+ }
+
+ /* Enable DA4 for IHFR */
+ if (channel_index & e_CHANNEL_2) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (EN_DA4 & initialVal_DA)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA4_REG,
+ SLOT11_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA4 from Slot 11 %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA4, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DA4 %d", error);
+ return error;
+ }
+
+ /* Power Up HFR Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ EN_HFR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up HFR Class-D Driver %d", error);
+ return error;
+ }
+
+ /* Power up HFR Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_HFR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up HFR Class D driver and digital path %d",
+ error);
+ return error;
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Power down IHF on a specific channel
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_ihf(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if IHF Power Down request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "IHF should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_DA & EN_DA3))
+ return 0;
+
+ /* Power Down HFL Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG, 0,
+ EN_HFL_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power Down HFL Class-D Driver %d",
+ error);
+ return error;
+ }
+
+ /* Power Down HFL Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_HFL_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power Down HFL Class D driver & digital path %d",
+ error);
+ return error;
+ }
+
+ /* Disable DA3 for IHFL */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA3);
+ if (0 != error) {
+ dev_err(dev, "Disable DA3 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA3_REG, 0,
+ SLOT10_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA3 cleared from Slot 10 %d",
+ error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if IHF is already powered Down */
+ if (!(initialVal_DA & EN_DA4))
+ return 0;
+
+ /* Power Down HFR Class-D Driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG, 0,
+ EN_HFR_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power Down HFR Class-D Driver %d",
+ error);
+ return error;
+ }
+
+ /* Power Down HFR Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_HFR_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power Down HFR Class D driver & digital path %d",
+ error);
+ return error;
+ }
+
+ /* Disable DA4 for IHFR */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA4);
+ if (0 != error) {
+ dev_err(dev, "Disable DA4 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA4_REG, 0,
+ SLOT11_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA4 cleared from Slot 11 %d",
+ error);
+ return error;
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Mute IHF on a specific channel
+ * @channel_index Channel-index
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_mute_ihf(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+
+ if ((channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ error = ste_audio_io_set_ihf_gain(channel_index, 0, -63,
+ 0, dev);
+ if (0 != error) {
+ dev_err(dev, "Mute ihf %d", error);
+ return error;
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Unmute IHF on a specific channel
+ * @channel_index Channel-index
+ * @gain Gain index of IHF
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_unmute_ihf(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ error = ste_audio_io_set_ihf_gain(channel_index, 0, gain[0],
+ 0, dev);
+ if (0 != error) {
+ dev_err(dev, "UnMute ihf %d", error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ error = ste_audio_io_set_ihf_gain(channel_index, 0, gain[1],
+ 0, dev);
+ if (0 != error) {
+ dev_err(dev, "UnMute ihf %d", error);
+ return error;
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Enable fading of IHF
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_enable_fade_ihf(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA3_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for HFL %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA4_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for HFR %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disable fading of IHF
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_disable_fade_ihf(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA3_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for HFL %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DA4_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for HFR %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up VIBL
+ * @channel_index Channel-index of VIBL
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_vibl(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if VibL PowerUp request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "VibL should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Try to allocate vibrator for audio left channel */
+ error = ste_audioio_vibrator_alloc(STE_AUDIOIO_CLIENT_AUDIO_L,
+ STE_AUDIOIO_CLIENT_AUDIO_R | STE_AUDIOIO_CLIENT_AUDIO_L);
+ if (error) {
+ dev_err(dev, " Couldn't allocate vibrator %d, client %d",
+ error, STE_AUDIOIO_CLIENT_AUDIO_L);
+ return error;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if VibL is already powered up */
+ if (initialVal_DA & EN_DA5)
+ return 0;
+
+ /* Enable DA5 for vibl */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG,
+ SLOT12_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA5 from Slot 12 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ EN_DA5, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DA5 for VibL %d", error);
+ return error;
+ }
+
+ /* Power Up VibL Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(
+ ANALOG_OUTPUT_ENABLE_REG, EN_VIBL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up VibL Class-D Driver %d", error);
+ return error;
+ }
+
+ /* Power up VibL Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_VIBL_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up VibL Class D driver and digital path %d",
+ error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power down VIBL
+ * @channel_index Channel-index of VIBL
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_vibl(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if VibL Power Down request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "VibL should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if VibL is already powered down */
+ if (!(initialVal_DA & EN_DA5))
+ return 0;
+
+
+ /* Power Down VibL Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG,
+ 0, EN_VIBL_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power Down VibL Class-D Driver %d", error);
+ return error;
+ }
+
+ /* Power Down VibL Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_VIBL_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power Down VibL Class D driver & digital path %d",
+ error);
+ return error;
+ }
+
+ /* Disable DA5 for VibL */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA5);
+ if (0 != error) {
+ dev_err(dev, "Disable DA5 for VibL %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG, 0,
+ SLOT12_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA5 cleared from Slot 12 %d", error);
+ return error;
+ }
+
+ /* Release vibrator */
+ ste_audioio_vibrator_release(STE_AUDIOIO_CLIENT_AUDIO_L);
+
+ return error;
+}
+/**
+ * @brief Enable fading of VIBL
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_enable_fade_vibl(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA5_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for VibL %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disable fading of VIBL
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_disable_fade_vibl(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA5_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for VibL %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up VIBR
+ * @channel_index Channel-index of VIBR
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_up_vibr(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if VibR PowerUp request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "VibR should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Try to allocate vibrator for audio right channel */
+ error = ste_audioio_vibrator_alloc(STE_AUDIOIO_CLIENT_AUDIO_R,
+ STE_AUDIOIO_CLIENT_AUDIO_R | STE_AUDIOIO_CLIENT_AUDIO_L);
+ if (error) {
+ dev_err(dev, " Couldn't allocate vibrator %d, client %d",
+ error, STE_AUDIOIO_CLIENT_AUDIO_R);
+ return error;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if VibR is already powered up */
+ if (initialVal_DA & EN_DA6)
+ return 0;
+
+ /* Enable DA6 for vibr */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG,
+ SLOT13_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA5 from Slot 13 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(
+ DIGITAL_DA_CHANNELS_ENABLE_REG, EN_DA6, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DA6 for VibR %d", error);
+ return error;
+ }
+
+ /* Power Up VibR Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(
+ ANALOG_OUTPUT_ENABLE_REG, EN_VIBR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up VibR Class-D Driver %d", error);
+ return error;
+ }
+
+ /* Power up VibR Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG,
+ EN_VIBR_MASK, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Power up VibR Class D driver & digital path %d",
+ error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power down VIBR
+ * @channel_index Channel-index of VIBR
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_vibr(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_DA = 0;
+
+ /* Check if VibR PowerDown request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "VibR should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_DA = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if VibR is already powered down */
+ if (!(initialVal_DA & EN_DA6))
+ return 0;
+
+
+ /* Power Down VibR Class-D driver */
+ error = HW_ACODEC_MODIFY_WRITE(ANALOG_OUTPUT_ENABLE_REG, 0,
+ EN_VIBR_MASK);
+ if (0 != error) {
+ dev_err(dev, "Power Down VibR Class-D Driver %d", error);
+ return error;
+ }
+
+ /* Power Down VibR Class D driver and digital path */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_OUTPUT_ENABLE_REG, 0,
+ EN_VIBR_MASK);
+ if (0 != error) {
+ dev_err(dev,
+ "Power Down VibR Class D driver & digital path %d",
+ error);
+ return error;
+ }
+
+ /* Disable DA6 for VibR */
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_DA_CHANNELS_ENABLE_REG,
+ 0, EN_DA6);
+ if (0 != error) {
+ dev_err(dev, "Disable DA6 for VibR %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG, 0,
+ SLOT13_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA5 cleared from Slot 13 %d",
+ error);
+ return error;
+ }
+
+ /* Release vibrator */
+ ste_audioio_vibrator_release(STE_AUDIOIO_CLIENT_AUDIO_R);
+
+ return error;
+}
+/**
+ * @brief Enable fading of VIBR
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_enable_fade_vibr(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA6_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for VibR %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disable fading of VIBR
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_disable_fade_vibr(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DA6_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for VibR %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up MIC1A
+ * @channel_index Channel-index of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_up_mic1a(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if Mic1 PowerUp request is mono channel */
+
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "MIC1 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ /* Check if Mic1 is already powered up or used by Dmic3 */
+ if (EN_AD3 & initialVal_AD)
+ return 0;
+
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, DATA_FROM_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Slot 02 outputs data from AD_OUT3 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD3, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD3 for Mic1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ SEL_DMIC3_FOR_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Select ADC1 for AD_OUT3 %d", error);
+ return error;
+ }
+
+ /* Select MIC1A */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ SEL_MIC1B_CLR_MIC1A);
+ if (0 != error) {
+ dev_err(dev, "Select MIC1A %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, EN_MIC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up Mic1 %d", error);
+ return error;
+ }
+
+ /* Power Up ADC1 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, POWER_UP_ADC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up ADC1 %d", error);
+ return error;
+ }
+
+return error;
+}
+/**
+ * @brief Power down MIC1A
+ * @channel_index Channel-index of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_down_mic1a(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if Mic1 PowerDown request is mono channel */
+
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic1 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ /* Check if Mic1 is already powered down or used by Dmic3 */
+ if (!(initialVal_AD & EN_AD3))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0, EN_MIC1);
+ if (0 != error) {
+ dev_err(dev, "Power Down Mic1 %d", error);
+ return error;
+ }
+
+ /* Power Down ADC1 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0, POWER_UP_ADC1);
+ if (0 != error) {
+ dev_err(dev, "Power Down ADC1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD3);
+ if (0 != error) {
+ dev_err(dev, "Disable AD3 for Mic1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG, 0,
+ DATA_FROM_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Slot 02 outputs data cleared from AD_OUT3 %d",
+ error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Mute MIC1A
+ * @channel_index Channel-index of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_mute_mic1a(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "MIC1 should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Mute mic1 */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, MUT_MIC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Mute Mic1 %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Unmute MIC1A
+ * @channel_index Channel-index of MIC1A
+ * @gain Gain index of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_unmute_mic1a(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic1 should have mono channel");
+ return -EINVAL;
+ }
+ /* UnMute mic1 */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0, MUT_MIC1);
+ if (0 != error) {
+ dev_err(dev, "UnMute Mic1 %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Enable fading of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_enable_fade_mic1a(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD3_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for Mic1 %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disable fading of MIC1A
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_disable_fade_mic1a(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD3_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for Mic1 %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power up MIC1B
+ * @channel_index Channel-index of MIC1B
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_mic1b(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error;
+ unsigned char initialVal_AD = 0;
+
+ error = regulator_enable(regulator_avsource);
+ if (0 != error) {
+ dev_err(dev, "regulator avsource enable failed = %d", error);
+ return error;
+ }
+ /* GPIO35 settings to enable MIC 1B input instead of TVOUT */
+ error = HW_ACODEC_MODIFY_WRITE(AB8500_GPIO_DIR5_REG,
+ GPIO35_DIR_OUTPUT, 0);
+ if (0 != error) {
+ dev_err(dev, "setting AB8500_GPIO_DIR5_REG reg %d", error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(AB8500_GPIO_OUT5_REG,
+ GPIO35_DIR_OUTPUT, 0);
+ if (0 != error) {
+ dev_err(dev, "setting AB8500_GPIO_OUT5_REG reg %d", error);
+ return error;
+ }
+
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic1 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ /* Check if Mic1 is already powered up or used by Dmic3 */
+ if (EN_AD3 & initialVal_AD)
+ return 0;
+
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, DATA_FROM_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Slot 02 outputs data from AD_OUT3 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD3, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD3 for Mic1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ SEL_DMIC3_FOR_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Select ADC1 for AD_OUT3 %d", error);
+ return error;
+ }
+
+ /* Select MIC1B */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, SEL_MIC1B_CLR_MIC1A,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Select MIC1B %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, EN_MIC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up Mic1 %d", error);
+ return error;
+ }
+
+ /* Power Up ADC1 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, POWER_UP_ADC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up ADC1 %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power down MIC1B
+ * @channel_index Channel-index of MIC1B
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_mic1b(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if Mic1 PowerDown request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic1 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if Mic1 is already powered down or used by Dmic3 */
+ if (!(initialVal_AD & EN_AD3))
+ return 0;
+
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0, EN_MIC1);
+ if (0 != error) {
+ dev_err(dev, "Power Down Mic1 %d", error);
+ return error;
+ }
+
+ /* Power Down ADC1 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0, POWER_UP_ADC1);
+ if (0 != error) {
+ dev_err(dev, "Power Down ADC1 %d", error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG, 0,
+ EN_AD3);
+ if (0 != error) {
+ dev_err(dev, "Disable AD3 for Mic1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG, 0,
+ DATA_FROM_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev, "Slot 02 outputs data cleared from AD_OUT3 %d",
+ error);
+ return error;
+ }
+
+ /* undo GPIO35 settings */
+ error = HW_ACODEC_MODIFY_WRITE(AB8500_GPIO_DIR5_REG,
+ 0, GPIO35_DIR_OUTPUT);
+ if (0 != error) {
+ dev_err(dev, "resetting AB8500_GPIO_DIR5_REG reg %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AB8500_GPIO_OUT5_REG,
+ 0, GPIO35_DIR_OUTPUT);
+ if (0 != error) {
+ dev_err(dev, "resetting AB8500_GPIO_OUT5_REG reg %d", error);
+ return error;
+ }
+
+ error = regulator_disable(regulator_avsource);
+ if (0 != error) {
+ dev_err(dev, "regulator avsource disable failed = %d", error);
+ return error;
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+/**
+ * @brief enable hardware loop of mic1b
+ * @chnl_index Channel-index of MIC1B
+ * @hw_loop type of hardware loop
+ * @loop_gain gain value to be used in hardware loop
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_enable_loop_mic1b(enum AUDIOIO_CH_INDEX chnl_index,
+ enum AUDIOIO_HAL_HW_LOOPS hw_loop,
+ int loop_gain, struct device *dev,
+ void *cookie)
+{
+ int error;
+ struct transducer_context_t *trnsdr;
+ trnsdr = (struct transducer_context_t *)cookie;
+
+ switch (hw_loop) {
+ /* Check if HSL is active */
+ case AUDIOIO_SIDETONE_LOOP:
+ if (!(trnsdr[HS_CH].is_power_up[e_CHANNEL_1])
+ && !(trnsdr[EAR_CH].is_power_up[e_CHANNEL_1])) {
+ error = -EFAULT;
+ dev_err(dev,
+ "HS or Earpiece not powered up error = %d",
+ error);
+ return error;
+ }
+
+ /* For ch1, Power On STFIR1, data comes from AD3*/
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG2,
+ FIR1_FROMAD3, 0);
+ if (error)
+ dev_err(dev, "FIR1 data comes from AD_OUT3 %d",
+ error);
+ error = HW_REG_WRITE(SIDETONE_FIR1_GAIN_REG, loop_gain);
+ if (error) {
+ dev_err(dev,
+ "Set FIR1 Gain index = %d",
+ error);
+ return error;
+ }
+ break;
+ default:
+ error = -EINVAL;
+ dev_err(dev, "loop not supported %d", error);
+ }
+ return error;
+}
+
+/**
+ * @brief disable hardware loop of mic1b
+ * @chnl_index Channel-index of MIC1B
+ * @hw_loop type of hardware loop
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_disable_loop_mic1b(enum AUDIOIO_CH_INDEX chnl_index,
+ enum AUDIOIO_HAL_HW_LOOPS hw_loop,
+ struct device *dev, void *cookie)
+{
+ int error;
+ struct transducer_context_t *trnsdr;
+ trnsdr = (struct transducer_context_t *)cookie;
+
+ switch (hw_loop) {
+ /* Check if HSL is active */
+ case AUDIOIO_SIDETONE_LOOP:
+ if (!trnsdr[HS_CH].is_power_up[e_CHANNEL_1]
+ && !trnsdr[EAR_CH].is_power_up[e_CHANNEL_1]) {
+ error = -EFAULT;
+ dev_err(dev, "HS or Earpiece not powered up, err = %d",
+ error);
+ return error;
+ }
+
+ /* For ch1, Power down STFIR1, data comes from AD3*/
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG2,
+ 0, FIR1_FROMAD3);
+ if (error) {
+ dev_err(dev, "FIR1 data comes from AD_OUT3, err = %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(FILTERS_CONTROL_REG,
+ 0, FIR_FILTERCONTROL);
+ if (error) {
+ dev_err(dev,
+ "ST FIR Filters disable failed %d", error);
+ return error;
+ }
+ break;
+ default:
+ error = -EINVAL;
+ dev_err(dev, "loop not supported %d", error);
+ }
+ return error;
+}
+
+/**
+ * @brief Power up MIC2
+ * @channel_index Channel-index of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_mic2(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if Mic2 PowerUp request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic2 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if Mic2 is already powered up or used by LINR or Dmic2 */
+ if (EN_AD2 & initialVal_AD)
+ return 0;
+
+
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, DATA_FROM_AD_OUT2);
+ if (0 != error) {
+ dev_err(dev, "Slot 01 outputs data from AD_OUT2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG, EN_AD2,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD2 for Mic2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ SEL_DMIC2_FOR_AD_OUT2);
+ if (0 != error) {
+ dev_err(dev, "Select ADC2 for AD_OUT2 %d", error);
+ return error;
+ }
+
+ /* Select mic2 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ SEL_LINR_CLR_MIC2);
+ if (0 != error) {
+ dev_err(dev, "Select MIC2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, EN_MIC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up Mic2 %d", error);
+ return error;
+ }
+
+ /* Power Up ADC1 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, POWER_UP_ADC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up ADC2 %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power down MIC2
+ * @channel_index Channel-index of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_power_down_mic2(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if Mic2 PowerDown request is mono channel */
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic2 should have mono channel");
+ return -EINVAL;
+ }
+
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+
+ /* Check if Mic2 is already powered down or used by LINR or Dmic2 */
+ if (!(initialVal_AD & EN_AD2))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0, EN_MIC2);
+ if (0 != error) {
+ dev_err(dev, "Power Down Mic2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD2);
+ if (0 != error) {
+ dev_err(dev, "Disable AD2 for Mic2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, 0,
+ (DATA_FROM_AD_OUT2<<4));
+ if (0 != error) {
+ dev_err(dev, "Slot 01 outputs data cleared from AD_OUT2 %d",
+ error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Mute MIC2
+ * @channel_index Channel-index of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_mute_mic2(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic2 should have mono channel");
+ return -EINVAL;
+ }
+
+ /* Mute mic2 */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, MUT_MIC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Mute Mic2 %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Unmute MIC2
+ * @channel_index Channel-index of MIC2
+ * @gain Gain index of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_unmute_mic2(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+ if (!(channel_index & e_CHANNEL_1)) {
+ dev_err(dev, "Mic2 should have mono channel");
+ return -EINVAL;
+ }
+ /* UnMute mic2 */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0, MUT_MIC2);
+ if (0 != error) {
+ dev_err(dev, "UnMute Mic2 %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Enable fading of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_enable_fade_mic2(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD2_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for Mic2 %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disable fading of MIC2
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_disable_fade_mic2(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD2_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for Mic2 %d", error);
+ return error;
+ }
+
+ return error;
+}
+/**
+ * @brief Power up LinIn
+ * @channel_index Channel-index of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_lin(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if LinIn PowerUp request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "LinIn should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ /* Enable AD1 for LinInL */
+ if (channel_index & e_CHANNEL_1) {
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (initialVal_AD & EN_AD1)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG,
+ DATA_FROM_AD_OUT1, 0);
+ if (0 != error) {
+ dev_err(dev, "Slot 00 outputs data from AD_OUT1 %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD1, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD1 for LinInL %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ SEL_DMIC1_FOR_AD_OUT1);
+ if (0 != error) {
+ dev_err(dev, "Select ADC3 for AD_OUT1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(
+ LINE_IN_MIC_CONF_REG, EN_LIN_IN_L, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up LinInL %d", error);
+ return error;
+ }
+
+ /* Power Up ADC3 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG,
+ POWER_UP_ADC3, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up ADC3 %d", error);
+ return error;
+ }
+ }
+ /* Enable AD2 for LinInR */
+
+ if (channel_index & e_CHANNEL_2) {
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (EN_AD2 & initialVal_AD)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG,
+ (DATA_FROM_AD_OUT2<<4), 0);
+ if (0 != error) {
+ dev_err(dev, "Slot 01 outputs data from AD_OUT2 %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD2, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD2 LinInR %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1, 0,
+ SEL_DMIC2_FOR_AD_OUT2);
+ if (0 != error) {
+ dev_err(dev, "Select ADC2 for AD_OUT2 %d", error);
+ return error;
+ }
+
+ /* Select LinInR */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG,
+ SEL_LINR_CLR_MIC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Select LinInR %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG,
+ EN_LIN_IN_R, 0);
+ if (0 != error) {
+ dev_err(dev, "Power up LinInR %d", error);
+ return error;
+ }
+
+ /* Power Up ADC2 */
+ error = HW_ACODEC_MODIFY_WRITE(
+ ADC_DAC_ENABLE_REG, POWER_UP_ADC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Power Up ADC2 %d", error);
+ return error;
+ }
+ }
+ return error;
+}
+/**
+ * @brief Power down LinIn
+ * @channel_index Channel-index of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_down_lin(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if LinIn PowerDown request is mono or Stereo channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "LinIn should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ /* Enable AD1 for LinInL */
+ if (channel_index & e_CHANNEL_1) {
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD1))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0,
+ EN_LIN_IN_L);
+ if (0 != error) {
+ dev_err(dev, "Power Down LinInL %d", error);
+ return error;
+ }
+
+ /* Power Down ADC3 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ POWER_UP_ADC3);
+ if (0 != error) {
+ dev_err(dev, "Power Down ADC3 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD1);
+ if (0 != error) {
+ dev_err(dev, "Disable AD1 for LinInL %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, 0,
+ DATA_FROM_AD_OUT1);
+ if (0 != error) {
+ dev_err(dev,
+ "Slot 00 outputs data cleared from AD_OUT1 %d",
+ error);
+ return error;
+ }
+ }
+
+ /* Enable AD2 for LinInR */
+ if (channel_index & e_CHANNEL_2) {
+ initialVal_AD = HW_REG_READ(DIGITAL_DA_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD2))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0,
+ EN_LIN_IN_R);
+ if (0 != error) {
+ dev_err(dev, "Power Down LinInR %d", error);
+ return error;
+ }
+
+ /* Power Down ADC2 */
+ error = HW_ACODEC_MODIFY_WRITE(ADC_DAC_ENABLE_REG, 0,
+ POWER_UP_ADC2);
+ if (0 != error) {
+ dev_err(dev, "Power Down ADC2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD2);
+ if (0 != error) {
+ dev_err(dev, "Disable AD2 LinInR %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, 0,
+ (DATA_FROM_AD_OUT2<<4));
+ if (0 != error) {
+ dev_err(dev,
+ "Slot01 outputs data cleared from AD_OUT2 %d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+/**
+ * @brief Mute LinIn
+ * @channel_index Channel-index of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_mute_lin(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "LinIn should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Mute LinInL */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG,
+ MUT_LIN_IN_L, 0);
+ if (0 != error) {
+ dev_err(dev, "Mute LinInL %d", error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* Mute LinInR */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG,
+ MUT_LIN_IN_R,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Mute LinInR %d", error);
+ return error;
+ }
+ }
+ return error;
+}
+/**
+ * @brief Unmute LinIn
+ * @channel_index Channel-index of LinIn
+ * @gain Gain index of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_unmute_lin(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "LinIn should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ /* UnMute LinInL */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0,
+ MUT_LIN_IN_L);
+ if (0 != error) {
+ dev_err(dev, "UnMute LinInL %d", error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* UnMute LinInR */
+ error = HW_ACODEC_MODIFY_WRITE(LINE_IN_MIC_CONF_REG, 0,
+ MUT_LIN_IN_R);
+ if (0 != error) {
+ dev_err(dev, "UnMute LinInR %d", error);
+ return error;
+ }
+ }
+ return error;
+}
+/**
+ * @brief Enables fading of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_enable_fade_lin(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD1_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for LinInL %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD2_DIGITAL_GAIN_REG, 0, DIS_FADING);
+ if (0 != error) {
+ dev_err(dev, "Enable fading for LinInR %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Disables fading of LinIn
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_disable_fade_lin(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD1_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for LinInL %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD2_DIGITAL_GAIN_REG, DIS_FADING, 0);
+ if (0 != error) {
+ dev_err(dev, "Disable fading for LinInR %d", error);
+ return error;
+ }
+ return error;
+}
+/**
+ * @brief Power Up DMIC12 LinIn
+ * @channel_index Channel-index of DMIC12
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_power_up_dmic12(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if DMic12 request is mono or Stereo */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "DMic12 does not support more than 2 channels");
+
+ return -EINVAL;
+ }
+
+ /* Setting Direction for GPIO pins on AB8500 */
+ error = HW_REG_WRITE(AB8500_GPIO_DIR4_REG, GPIO27_DIR_OUTPUT);
+ if (0 != error) {
+ dev_err(dev, "Setting Direction for GPIO pins on AB8500 %d",
+ error);
+ return error;
+ }
+
+ /* Enable AD1 for Dmic1 */
+ if (channel_index & e_CHANNEL_1) {
+ /* Check if DMIC1 is already powered up or used by LinInL */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (initialVal_AD & EN_AD1)
+ return 0;
+
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG,
+ DATA_FROM_AD_OUT1);
+ if (0 != error) {
+ dev_err(dev, "Slot 00 outputs data from AD_OUT1 %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD1, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD1 for DMIC1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ SEL_DMIC1_FOR_AD_OUT1, 0);
+ if (0 != error) {
+ dev_err(dev, "Select DMIC1 for AD_OUT1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, EN_DMIC1, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC1 %d", error);
+ return error;
+ }
+ }
+ /* Enable AD2 for Dmic2 */
+
+ if (channel_index & e_CHANNEL_2) {
+ /* Check if DMIC2 is already powered up
+ or used by Mic2 or LinInR */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (initialVal_AD & EN_AD2)
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG,
+ (DATA_FROM_AD_OUT2<<4), 0);
+ if (0 != error) {
+ dev_err(dev, "Slot 01 outputs data from AD_OUT2 %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD2, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD2 for DMIC2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ SEL_DMIC2_FOR_AD_OUT2, 0);
+ if (0 != error) {
+ dev_err(dev, "Select DMIC2 for AD_OUT2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, EN_DMIC2, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC2 %d", error);
+ return error;
+ }
+ }
+
+ return error;
+}
+/**
+ * @brief Power down DMIC12 LinIn
+ * @channel_index Channel-index of DMIC12
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_power_down_dmic12(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if DMic12 request is mono or Stereo or multi channel */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "DMic12 does not support more than 2 channels");
+
+ return -EINVAL;
+ }
+
+ /* Setting Direction for GPIO pins on AB8500 */
+ error = HW_ACODEC_MODIFY_WRITE(AB8500_GPIO_DIR4_REG, 0,
+ GPIO27_DIR_OUTPUT);
+ if (0 != error) {
+ dev_err(dev, "Clearing Direction for GPIO pins on AB8500 %d",
+ error);
+ return error;
+ }
+ /* Enable AD1 for Dmic1 */
+ if (channel_index & e_CHANNEL_1) {
+ /* Check if DMIC1 is already powered Down or used by LinInL */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD1))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, 0, EN_DMIC1);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD1);
+ if (0 != error) {
+ dev_err(dev, "Disable AD1 for DMIC1 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, 0,
+ DATA_FROM_AD_OUT1);
+ if (0 != error) {
+ dev_err(dev,
+ "Slot 00 outputs data cleared from AD_OUT1 %d",
+ error);
+ return error;
+ }
+ }
+
+ /* Enable AD2 for Dmic2 */
+ if (channel_index & e_CHANNEL_2) {
+ /* MIC2 is already powered Down or used by Mic2 or LinInR */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD2))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, 0, EN_DMIC2);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD2);
+ if (0 != error) {
+ dev_err(dev, "Disable AD2 for DMIC2 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT0_1_REG, 0,
+ (DATA_FROM_AD_OUT2<<4));
+ if (0 != error) {
+ dev_err(dev,
+ "Slot 01 outputs data cleared from AD_OUT2 %d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+/**
+ * @brief Get headset gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_get_headset_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ int i = 0;
+ if (gain_index == 0) {
+
+ *left_volume = 0 - HW_REG_READ(DA1_DIGITAL_GAIN_REG);
+ *right_volume = 0 - HW_REG_READ(DA2_DIGITAL_GAIN_REG);
+
+ }
+
+ if (gain_index == 1) {
+ *left_volume = 8 - HW_REG_READ(HSL_EAR_DIGITAL_GAIN_REG);
+ *right_volume = 8 - HW_REG_READ(HSR_DIGITAL_GAIN_REG);
+ }
+
+ if (gain_index == 2) {
+ i = (HW_REG_READ(ANALOG_HS_GAIN_REG)>>4);
+ *left_volume = hs_analog_gain_table[i];
+ i = (HW_REG_READ(ANALOG_HS_GAIN_REG) & MASK_QUARTET0);
+ *right_volume = hs_analog_gain_table[i];
+ }
+ return 0;
+}
+/**
+ * @brief Get earpiece gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_get_earpiece_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ if (0 == gain_index)
+ *left_volume = 0 - HW_REG_READ(DA1_DIGITAL_GAIN_REG);
+ if (1 == gain_index)
+ *left_volume = 8 - HW_REG_READ(HSL_EAR_DIGITAL_GAIN_REG);
+ return 0;
+}
+/**
+ * @brief Get ihf gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_get_ihf_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+
+ *left_volume = 0 - HW_REG_READ(DA3_DIGITAL_GAIN_REG);
+ *right_volume = 0 - HW_REG_READ(DA4_DIGITAL_GAIN_REG);
+ return 0;
+}
+/**
+ * @brief Get vibl gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_get_vibl_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+
+ *left_volume = 0 - HW_REG_READ(DA5_DIGITAL_GAIN_REG);
+
+ return 0;
+}
+/**
+ * @brief Get vibr gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_get_vibr_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+
+ *right_volume = 0 - HW_REG_READ(DA6_DIGITAL_GAIN_REG);
+ return 0;
+}
+/**
+ * @brief Get MIC1A & MIC2A gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_get_mic1a_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ if (gain_index == 0)
+ *left_volume = 31 - HW_REG_READ(AD3_DIGITAL_GAIN_REG);
+ if (gain_index == 1)
+ *left_volume = HW_REG_READ(ANALOG_MIC1_GAIN_REG);
+
+ return 0;
+}
+/**
+ * @brief Get MIC2 gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_get_mic2_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ if (gain_index == 0)
+ *left_volume = 31 - HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+ if (gain_index == 1)
+ *left_volume = HW_REG_READ(ANALOG_MIC2_GAIN_REG);
+
+ return 0;
+}
+/**
+ * @brief Get Lin IN gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_get_lin_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ if (gain_index == 0) {
+ *left_volume = 31 - HW_REG_READ(AD1_DIGITAL_GAIN_REG);
+ *right_volume = 31 - HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+ }
+
+ if (gain_index == 0) {
+ *left_volume = 2 * ((HW_REG_READ(ANALOG_HS_GAIN_REG)>>4) - 5);
+ *right_volume = 2 * (HW_REG_READ(ANALOG_LINE_IN_GAIN_REG) - 5);
+ }
+
+ return 0;
+}
+/**
+ * @brief Get DMIC12 gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_get_dmic12_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+
+ *left_volume = HW_REG_READ(AD1_DIGITAL_GAIN_REG);
+
+ *right_volume = HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+
+ return 0;
+}
+/**
+ * @brief Get DMIC34 gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_get_dmic34_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ *left_volume = HW_REG_READ(AD3_DIGITAL_GAIN_REG);
+ *right_volume = HW_REG_READ(AD4_DIGITAL_GAIN_REG);
+
+ return 0;
+}
+/**
+ * @brief Get DMIC56 gain
+ * @left_volume
+ * @right_volume
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_get_dmic56_gain(int *left_volume, int *right_volume,
+ u16 gain_index, struct device *dev)
+{
+ *left_volume = HW_REG_READ(AD5_DIGITAL_GAIN_REG);
+
+ *right_volume = HW_REG_READ(AD6_DIGITAL_GAIN_REG);
+ return 0;
+}
+/**
+ * @brief Set gain of headset along a specified channel
+ * @channel_index Channel-index of headset
+ * @gain_index Gain index of headset
+ * @gain_value Gain value of headset
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+
+int ste_audio_io_set_headset_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+ int i = 0;
+ int acodec_device_id;
+
+ acodec_device_id = abx500_get_chip_id(dev);
+
+ if (channel_index & e_CHANNEL_1) {
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA1_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(DA1_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSL gainindex = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+
+ if (gain_index == 1) {
+ int gain = 0;
+ gain = 8 - gain_value;
+
+ initial_val = HW_REG_READ(HSL_EAR_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(HSL_EAR_DIGITAL_GAIN_REG,
+ ((initial_val & (~HS_DIGITAL_GAIN_MASK)) | (gain &
+ HS_DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSL gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+
+ if (gain_index == 2) {
+ /* Set Analog gain */
+ int gain = -1;
+
+ if (gain_value % 2) {
+ gain_value -= 1;
+ dev_err(dev,
+ "Odd Gain received.Fixing it to 2dB step gain_value = %d",
+ gain_value);
+ }
+ /* Fix for 4dB step gains. Select one lower value */
+ if (gain_value == -22)
+ gain_value = -24;
+
+ if (gain_value == -26)
+ gain_value = -28;
+
+ if (gain_value == -30)
+ gain_value = -32;
+
+ for (i = 0 ; i < 16; i++) {
+ if (hs_analog_gain_table[i] == gain_value) {
+ gain = i<<4;
+ break;
+ }
+ }
+ if (gain == -1)
+ return -1;
+
+ if ((AB8500_REV_10 == acodec_device_id) ||
+ (AB8500_REV_11 == acodec_device_id)) {
+ if (!gain)
+ gain = 0x10;
+ gain = 0xF0 - gain;
+ }
+ initial_val = HW_REG_READ(ANALOG_HS_GAIN_REG);
+
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_HS_GAIN_REG, ((initial_val &
+ (~L_ANALOG_GAIN_MASK)) | (gain & L_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSL gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ /* for HSR */
+ if (channel_index & e_CHANNEL_2) {
+ /* Set Gain HSR */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA2_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(DA2_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSR gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+
+ if (gain_index == 1) {
+ int gain = 0;
+ gain = 8 - gain_value;
+
+ initial_val = HW_REG_READ(HSR_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(HSR_DIGITAL_GAIN_REG, ((initial_val
+ & (~HS_DIGITAL_GAIN_MASK)) | (gain &
+ HS_DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSR gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+
+ }
+
+ if (gain_index == 2) {
+ /* Set Analog gain */
+ int gain = -1;
+
+ if (gain_value % 2) {
+ gain_value -= 1;
+ dev_err(dev,
+ "Odd Gain received.Fixing it to 2dB step gain_value = %d",
+ gain_value);
+ }
+ /* Fix for 4dB step gains. Select one lower value */
+ if (gain_value == -22)
+ gain_value = -24;
+
+ if (gain_value == -26)
+ gain_value = -28;
+
+ if (gain_value == -30)
+ gain_value = -32;
+
+ for (i = 0 ; i < 16 ; i++) {
+ if (hs_analog_gain_table[i] == gain_value) {
+ gain = i;
+ break;
+ }
+ }
+ if (gain == -1)
+ return -1;
+
+ if ((AB8500_REV_10 == acodec_device_id) ||
+ (AB8500_REV_11 == acodec_device_id)) {
+ if (!gain)
+ gain = 1;
+ gain = 0x0F - gain;
+ }
+ initial_val = HW_REG_READ(ANALOG_HS_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_HS_GAIN_REG, ((initial_val &
+ (~R_ANALOG_GAIN_MASK)) | (gain & R_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain HSR gainindex = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Set gain of earpiece
+ * @channel_index Channel-index of earpiece
+ * @gain_index Gain index of earpiece
+ * @gain_value Gain value of earpiece
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_earpiece_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+ if (channel_index & e_CHANNEL_1) {
+ if (0 == gain_index) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA1_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(DA1_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Ear gainindex = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+
+ if (gain_index == 1) {
+ int gain = 0;
+ gain = 8 - gain_value;
+
+ initial_val = HW_REG_READ(HSL_EAR_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(HSL_EAR_DIGITAL_GAIN_REG,
+ ((initial_val & (~HS_DIGITAL_GAIN_MASK)) | (gain &
+ HS_DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Ear gainindex = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+/**
+ * @brief Set gain of vibl
+ * @channel_index Channel-index of vibl
+ * @gain_index Gain index of vibl
+ * @gain_value Gain value of vibl
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_vibl_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain vibl */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA5_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(DA5_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain VibL gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ return error;
+}
+/**
+ * @brief Set gain of vibr
+ * @channel_index Channel-index of vibr
+ * @gain_index Gain index of vibr
+ * @gain_value Gain value of vibr
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_set_vibr_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value,
+ u32 linear,
+ struct device *dev)
+{
+
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain vibr */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA6_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(DA6_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain VibR gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ return error;
+}
+/**
+ * @brief Set gain of ihf along a specified channel
+ * @channel_index Channel-index of ihf
+ * @gain_index Gain index of ihf
+ * @gain_value Gain value of ihf
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_ihf_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain IHFL */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA3_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(DA3_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain IHFL gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+
+ }
+ }
+ if (channel_index & e_CHANNEL_2) {
+ /* Set Gain IHFR */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 0 - gain_value;
+
+ initial_val = HW_REG_READ(DA4_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(DA4_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain IHFR gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+/**
+ * @brief Set gain of MIC1A & MIC1B
+ * @channel_index Channel-index of MIC1
+ * @gain_index Gain index of MIC1
+ * @gain_value Gain value of MIC1
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_mic1a_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain mic1 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD3_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(AD3_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Mic1 gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+
+ }
+
+ if (gain_index == 1) {
+ /* Set Analog gain */
+ initial_val = HW_REG_READ(ANALOG_MIC1_GAIN_REG);
+
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_MIC1_GAIN_REG, ((initial_val
+ & (~MIC_ANALOG_GAIN_MASK)) | (gain_value &
+ MIC_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Mic1 gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ return error;
+}
+/**
+ * @brief Set gain of MIC2
+ * @channel_index Channel-index of MIC2
+ * @gain_index Gain index of MIC2
+ * @gain_value Gain value of MIC2
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_mic2_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value,
+ u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain mic2 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(AD2_DIGITAL_GAIN_REG, ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Mic2 gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+
+ }
+
+ if (gain_index == 1) {
+ /* Set Analog gain */
+ initial_val = HW_REG_READ(ANALOG_MIC2_GAIN_REG);
+
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_MIC2_GAIN_REG, ((initial_val
+ & (~MIC_ANALOG_GAIN_MASK)) | (gain_value &
+ MIC_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain Mic2 gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ return error;
+}
+/**
+ * @brief Set gain of Lin IN along a specified channel
+ * @channel_index Channel-index of Lin In
+ * @gain_index Gain index of Lin In
+ * @gain_value Gain value of Lin In
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_lin_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD1_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(AD1_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain LinInL gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+
+ }
+
+ if (gain_index == 1) {
+ int gain = 0;
+ /*
+ * Converting -10 to 20 range into 0 - 15
+ * & shifting it left by 4 bits
+ */
+ gain = ((gain_value/2) + 5)<<4;
+
+ initial_val = HW_REG_READ(ANALOG_LINE_IN_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_LINE_IN_GAIN_REG,
+ ((initial_val & (~L_ANALOG_GAIN_MASK)) | (gain &
+ L_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain LinInL gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* Set Gain LinInR */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(AD2_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain LinInR gain index = %d%d",
+ gain_index, error);
+ return error;
+ }
+ }
+ if (gain_index == 1) {
+ int gain = 0;
+ /* Converting -10 to 20 range into 0 - 15 */
+ gain = ((gain_value/2) + 5);
+
+ initial_val = HW_REG_READ(ANALOG_LINE_IN_GAIN_REG);
+ /* Write gain */
+ error = HW_REG_WRITE(ANALOG_LINE_IN_GAIN_REG,
+ ((initial_val & (~R_ANALOG_GAIN_MASK)) | (gain &
+ R_ANALOG_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain LinInR gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+/**
+ * @brief Set gain of DMIC12 along a specified channel
+ * @channel_index Channel-index of DMIC12
+ * @gain_index Gain index of DMIC12
+ * @gain_value Gain value of DMIC12
+ * @linear
+ * @return 0 on success otherwise negative error code
+ */
+
+int ste_audio_io_set_dmic12_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain Dmic1 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD1_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(AD1_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain DMic1 gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ if (channel_index & e_CHANNEL_2) {
+ /* Set Gain Dmic2 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD2_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(AD2_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain DMic2 gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+ return error;
+}
+
+int ste_audio_io_switch_to_burst_mode_headset(int burst_fifo_switch_frame,
+ struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_INT_CONTROL_REG,
+ WAKEUP_SIGNAL_SAMPLE_COUNT, 0);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_LENGTH_REG,
+ BURST_FIFO_TRANSFER_LENGTH, 0);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_CONTROL_REG,
+ (BURST_FIFO_INF_RUNNING | BURST_FIFO_INF_IN_MASTER_MODE
+ |PRE_BIT_CLK0_COUNT), 0);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_WAKE_UP_DELAY_REG,
+ BURST_FIFO_WAKUP_DEALAY, 0);
+ if (0 != error)
+ return error;
+
+ error = HW_REG_WRITE(BURST_FIFO_SWITCH_FRAME_REG,
+ burst_fifo_switch_frame);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(TDM_IF_BYPASS_B_FIFO_REG,
+ IF0_BFifoEn, 0);
+ if (0 != error)
+ return error;
+
+ return error;
+}
+int ste_audio_io_switch_to_normal_mode_headset(
+ struct device *dev)
+{
+ int error = 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(TDM_IF_BYPASS_B_FIFO_REG, 0,
+ IF0_BFifoEn);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_INT_CONTROL_REG,
+ 0, WAKEUP_SIGNAL_SAMPLE_COUNT);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_LENGTH_REG,
+ 0, BURST_FIFO_TRANSFER_LENGTH);
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_CONTROL_REG, 0,
+ (BURST_FIFO_INF_RUNNING | BURST_FIFO_INF_IN_MASTER_MODE
+ |PRE_BIT_CLK0_COUNT));
+ if (0 != error)
+ return error;
+
+ error = HW_ACODEC_MODIFY_WRITE(BURST_FIFO_WAKE_UP_DELAY_REG,
+ 0, BURST_FIFO_WAKUP_DEALAY);
+ if (0 != error)
+ return error;
+
+ return error;
+}
+
+
+int ste_audio_io_mute_vibl(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_unmute_vibl(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_mute_vibr(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_unmute_vibr(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_mute_dmic12(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ if ((channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ error = ste_audio_io_set_dmic12_gain(channel_index, 0, -32,
+ 0, dev);
+ if (0 != error) {
+ dev_err(dev, "Mute dmic12 %d", error);
+ return error;
+ }
+ }
+
+ return error;
+
+}
+
+int ste_audio_io_unmute_dmic12(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+ if ((channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ error = ste_audio_io_set_dmic12_gain(channel_index,
+ 0, gain[0], 0, dev);
+ if (0 != error) {
+ dev_err(dev, "UnMute dmic12 %d", error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_enable_fade_dmic12(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_disable_fade_dmic12(struct device *dev)
+{
+ return 0;
+}
+
+/**
+ * @brief enable hardware loop of dmic12
+ * @chnl_index Channel-index of dmic12
+ * @hw_loop type of hardware loop
+ * @loop_gain gain value to be used in hardware loop
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_enable_loop_dmic12(enum AUDIOIO_CH_INDEX chnl_index,
+ enum AUDIOIO_HAL_HW_LOOPS hw_loop,
+ int loop_gain, struct device *dev,
+ void *cookie)
+{
+ int error = 0;
+ struct transducer_context_t *trnsdr;
+ trnsdr = (struct transducer_context_t *)cookie;
+
+ switch (hw_loop) {
+ /* Check if HSL is active */
+ case AUDIOIO_SIDETONE_LOOP:
+ if (!trnsdr[HS_CH].is_power_up[e_CHANNEL_1]
+ && !trnsdr[EAR_CH].is_power_up[e_CHANNEL_1]) {
+ error = -EFAULT;
+ dev_err(dev,
+ "Sidetone enable needs HS or Earpiece powered up, err = %d",
+ error);
+ return error;
+ }
+
+ if (chnl_index & e_CHANNEL_1) {
+ /* For ch1, Power On STFIR1, data comes from AD1*/
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG2,
+ 0, FIR1_FROMAD1);
+ if (error) {
+ dev_err(dev, "FIR1 data comes from AD_OUT1 %d",
+ error);
+ return error;
+ }
+
+ error = HW_REG_WRITE(SIDETONE_FIR1_GAIN_REG, loop_gain);
+ if (error) {
+ dev_err(dev,
+ "Set FIR1 Gain index = %d", error);
+ return error;
+ }
+ }
+
+ if (chnl_index & e_CHANNEL_2) {
+ /* For ch2, Power On STFIR1, data comes from AD2*/
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG2,
+ 0, FIR1_FROMAD2);
+ if (error) {
+ dev_err(dev, "FIR1 data comes from AD_OUT2 %d",
+ error);
+ return error;
+ }
+ error = HW_REG_WRITE(SIDETONE_FIR2_GAIN_REG, loop_gain);
+ if (error) {
+ dev_err(dev,
+ "Set FIR2 Gain error = %d", error);
+ return error;
+ }
+ }
+ break;
+ default:
+ error = -EINVAL;
+ dev_err(dev, "loop not supported %d", error);
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+/**
+ * @brief disable hardware loop of dmic12
+ * @chnl_index Channel-index of dmic12
+ * @hw_loop type of hardware loop
+ * @return 0 on success otherwise negative error code
+ */
+int ste_audio_io_disable_loop_dmic12(enum AUDIOIO_CH_INDEX chnl_index,
+ enum AUDIOIO_HAL_HW_LOOPS hw_loop,
+ struct device *dev, void *cookie)
+{
+ int error = -EINVAL;
+ struct transducer_context_t *trnsdr;
+ trnsdr = (struct transducer_context_t *)cookie;
+
+ switch (hw_loop) {
+ /* Check if HSL is active */
+ case AUDIOIO_SIDETONE_LOOP:
+ if (!trnsdr[HS_CH].is_power_up[e_CHANNEL_1]
+ && !trnsdr[EAR_CH].is_power_up[e_CHANNEL_1]) {
+ error = -EFAULT;
+ dev_err(dev,
+ "Sidetone disable needs HS or Earpiece powered up, err = %d",
+ error);
+ return error;
+ }
+
+ if (chnl_index & e_CHANNEL_1) {
+ /* For ch1, Power On STFIR1, data comes from AD1*/
+ error =
+ HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG2,
+ 0, FIR1_FROMAD1);
+ if (error)
+ dev_err(dev, "FIR1 data comes from AD_OUT1 %d",
+ error);
+ }
+
+ if (chnl_index & e_CHANNEL_2) {
+ /* For ch2, Power On STFIR1, data comes from AD2*/
+ error =
+ HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG2,
+ 0, FIR1_FROMAD2);
+ if (error)
+ dev_err(dev, "FIR1 data comes from AD_OUT2 %d",
+ error);
+ }
+ error = HW_ACODEC_MODIFY_WRITE(FILTERS_CONTROL_REG,
+ 0, FIR_FILTERCONTROL);
+ if (error) {
+ dev_err(dev,
+ "ST FIR Filters disable failed %d", error);
+ return error;
+ }
+ break;
+ default:
+ dev_err(dev, "loop not supported %d", error);
+ }
+ dump_acodec_registers(__func__, dev);
+ return error;
+}
+
+int ste_audio_io_power_up_dmic34(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ /* Check if DMic34 request is mono or Stereo */
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "DMic34 does not support more than 2 channels");
+ return -EINVAL;
+ }
+
+ /* Setting Direction for GPIO pins on AB8500 */
+ error = HW_REG_WRITE(AB8500_GPIO_DIR4_REG, GPIO29_DIR_OUTPUT);
+ if (0 != error) {
+ dev_err(dev, "Setting Direction for GPIO pins on AB8500 %d",
+ error);
+ return error;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Check if DMIC3 is already powered up or used by Mic1A
+ or Mic1B */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+
+ if (initialVal_AD & (EN_AD3))
+ return 0;
+
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG,
+ DATA_FROM_AD_OUT3, 0);
+ if (0 != error) {
+ dev_err(dev, "Slot 02 outputs data from AD_OUT3 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG, EN_AD3,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD3 for DMIC3 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_MUXES_REG1,
+ SEL_DMIC3_FOR_AD_OUT3,
+ 0);
+ if (0 != error) {
+ dev_err(dev, "Select DMIC3 for AD_OUT3 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, EN_DMIC3, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC3 %d", error);
+ return error;
+ }
+}
+
+ /* Enable AD4 for Dmic4 */
+ if (channel_index & e_CHANNEL_2) {
+ /* Check if DMIC4 is already powered up */
+ if (initialVal_AD & (EN_AD4))
+ return 0;
+
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG,
+ (DATA_FROM_AD_OUT4<<4), 0);
+ if (0 != error) {
+ dev_err(dev, "Slot 03 outputs data from AD_OUT4 %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ EN_AD4, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable AD4 for DMIC4 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, EN_DMIC4, 0);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC4 %d", error);
+ return error;
+ }
+ }
+ return error;
+}
+
+int ste_audio_io_power_down_dmic34(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "DMic34 does not support more than 2 channels");
+ return -EINVAL;
+ }
+
+ /* Setting Direction for GPIO pins on AB8500 */
+ error = HW_ACODEC_MODIFY_WRITE(AB8500_GPIO_DIR4_REG, 0,
+ GPIO29_DIR_OUTPUT);
+ if (0 != error) {
+ dev_err(dev, "Clearing Direction for GPIO pins on AB8500 %d",
+ error);
+ return error;
+ }
+
+ /* Enable AD1 for Dmic1 */
+ if (channel_index & e_CHANNEL_1) {
+ /* Check if DMIC3 is already powered Down or used by Mic1A
+ or Mic1B */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD3))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, 0, EN_DMIC3);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC3 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0,
+ EN_AD3);
+ if (0 != error) {
+ dev_err(dev, "Disable AD3 for DMIC3 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG, 0,
+ DATA_FROM_AD_OUT3);
+ if (0 != error) {
+ dev_err(dev,
+ "Slot 02 outputs data cleared from AD_OUT3 %d",
+ error);
+ return error;
+ }
+ }
+
+ /* Enable AD4 for Dmic4 */
+ if (channel_index & e_CHANNEL_2) {
+ /* Check if DMIC4 is already powered down */
+ initialVal_AD = HW_REG_READ(DIGITAL_AD_CHANNELS_ENABLE_REG);
+ if (!(initialVal_AD & EN_AD4))
+ return 0;
+
+ error = HW_ACODEC_MODIFY_WRITE(DMIC_ENABLE_REG, 0, EN_DMIC4);
+ if (0 != error) {
+ dev_err(dev, "Enable DMIC4 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(DIGITAL_AD_CHANNELS_ENABLE_REG,
+ 0, EN_AD4);
+ if (0 != error) {
+ dev_err(dev, "Disable AD4 for DMIC4 %d", error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT2_3_REG, 0,
+ (DATA_FROM_AD_OUT4<<4));
+ if (0 != error) {
+ dev_err(dev,
+ "Slot 03 outputs data cleared from AD_OUT4 %d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_set_dmic34_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initial_val = 0;
+
+ if (channel_index & e_CHANNEL_1) {
+ /* Set Gain Dmic3 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD3_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(AD3_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain DMic3 gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* Set Gain Dmic4 */
+ if (gain_index == 0) {
+ int gain = 0;
+ gain = 31 - gain_value;
+
+ initial_val = HW_REG_READ(AD4_DIGITAL_GAIN_REG);
+ error = HW_REG_WRITE(AD4_DIGITAL_GAIN_REG,
+ ((initial_val
+ & (~DIGITAL_GAIN_MASK)) | (gain & DIGITAL_GAIN_MASK)));
+
+ if (0 != error) {
+ dev_err(dev,
+ "Set Gain DMic4 gain index = %d %d",
+ gain_index, error);
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+int ste_audio_io_mute_dmic34(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ if ((channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ error = ste_audio_io_set_dmic34_gain(channel_index, 0, -32,
+ 0, dev);
+ if (0 != error) {
+ dev_err(dev, "Mute dmic34 %d", error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_unmute_dmic34(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ int error = 0;
+ if ((channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ error = ste_audio_io_set_dmic34_gain(channel_index,
+ 0, gain[0], 0, dev);
+ if (0 != error) {
+ dev_err(dev, "UnMute dmic34 %d", error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_enable_fade_dmic34(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_disable_fade_dmic34(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_power_up_dmic56(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_power_down_dmic56(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_set_dmic56_gain(enum AUDIOIO_CH_INDEX channel_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_mute_dmic56(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_unmute_dmic56(enum AUDIOIO_CH_INDEX channel_index, int *gain,
+ struct device *dev)
+{
+ return 0;
+}
+int ste_audio_io_enable_fade_dmic56(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_disable_fade_dmic56(struct device *dev)
+{
+ return 0;
+}
+
+int ste_audio_io_configure_if1(struct device *dev)
+{
+ int error = 0;
+
+ error = HW_REG_WRITE(IF1_CONF_REG, IF_DELAYED |
+ I2S_LEFT_ALIGNED_FORMAT | WORD_LENGTH_16);
+ if (error != 0) {
+ dev_err(dev,
+ "Configure IF1: I2S Format 16 Bits word length error = %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(TDM_IF_BYPASS_B_FIFO_REG, IF1_MASTER, 0);
+ if (error != 0) {
+ dev_err(dev,
+ "Configure IF1: IF1 master error = %d",
+ error);
+ return error;
+ }
+
+ error = HW_ACODEC_MODIFY_WRITE(IF0_IF1_MASTER_CONF_REG,
+ EN_FSYNC_BITCLK1, 0);
+ if (error != 0) {
+ dev_err(dev,
+ "ConfigIF1 bitclk is 32x48KHz, enable Fsync1 and Bitclk1 error = %d",
+ error);
+ return error;
+ }
+ return error;
+}
+
+int ste_audio_io_power_up_fmrx(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal = 0;
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "FMRX should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ ste_audio_io_configure_if1(dev);
+
+ if (channel_index & e_CHANNEL_1) {
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA7_REG,
+ SLOT24_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA_IN7 from Slot 24 %d",
+ error);
+ return error;
+ }
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG,
+ SEL_AD_OUT8_FROM_DAIN7, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to AD_OUT5 from DA_IN7 %d",
+ error);
+ return error;
+ }
+
+ initialVal = HW_REG_READ(AD_ALLOCATION_TO_SLOT6_7_REG);
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT6_7_REG,
+ ((initialVal & MASK_QUARTET1)|SEL_IF6_FROM_AD_OUT5));
+ if (0 != error) {
+ dev_err(dev, "Data sent to IF slot 6 from AD_OUT5 %d",
+ error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA8_REG,
+ SLOT25_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA_IN8 from Slot 25 %d",
+ error);
+ return error;
+ }
+
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG,
+ SEL_AD_OUT6_FROM_DAIN8, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to AD_OUT6 from DA_IN8 %d",
+ error);
+ return error;
+ }
+
+ initialVal = HW_REG_READ(AD_ALLOCATION_TO_SLOT6_7_REG);
+
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT6_7_REG,
+ (initialVal & MASK_QUARTET0)|SEL_IF7_FROM_AD_OUT6);
+ /* 5x is written */
+ if (0 != error) {
+ dev_err(dev, "Data sent to IF7 from AD_OUT6 %d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_power_down_fmrx(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "FMRX should have mono or stereo channels");
+ return -EINVAL;
+ }
+ if (channel_index & e_CHANNEL_1) {
+ /* data sent to DA7 input of DA filter form IF1 */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA7_REG, 0,
+ SLOT24_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev, "Clearing Data sent to DA_IN7 from Slot 24 %d",
+ error);
+ return error;
+ }
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG, 0,
+ SEL_AD_OUT8_FROM_DAIN7);
+ if (0 != error) {
+ dev_err(dev, "Clearing Data sent to AD_OUT5 from DA_IN7 %d",
+ error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT6_7_REG, 0,
+ SEL_IF6_FROM_AD_OUT5);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to IF slot 6 from AD_OUT5 %d",
+ error);
+ return error;
+ }
+}
+
+ if (channel_index & e_CHANNEL_2) {
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA8_REG, 0,
+ SLOT25_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to DA_IN8 from Slot 25 %d",
+ error);
+ return error;
+ }
+
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG, 0,
+ SEL_AD_OUT6_FROM_DAIN8);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to AD_OUT6 from DA_IN8 %d",
+ error);
+ return error;
+ }
+ error = HW_ACODEC_MODIFY_WRITE(AD_ALLOCATION_TO_SLOT6_7_REG, 0,
+ SEL_IF7_FROM_AD_OUT6);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to IF7 from AD_OUT6 %d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+
+int ste_audio_io_power_up_fmtx(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal = 0;
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "FMTX should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ ste_audio_io_configure_if1(dev);
+
+ if (channel_index & e_CHANNEL_1) {
+ /* data sent to DA7 input of DA filter form IF1 14 slot */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA7_REG,
+ SLOT14_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev,
+ "Data sent to DA_IN7 from Slot 14 %d", error);
+ return error;
+ }
+ /* DA_IN7 to AD_OUT5 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG,
+ SEL_AD_OUT5_FROM_DAIN7, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to AD_OUT5 from DA_IN7 %d",
+ error);
+ return error;
+ }
+
+ initialVal = HW_REG_READ(AD_ALLOCATION_TO_SLOT16_17_REG);
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT16_17_REG,
+ (initialVal & MASK_QUARTET1)|SEL_IF6_FROM_AD_OUT5);
+ if (0 != error) {
+ dev_err(dev, "Data sent to IF16 from AD_OUT5 %d",
+ error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* data sent to DA8 input of DA filter */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA8_REG,
+ SLOT15_FOR_DA_PATH, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to DA_IN8 from Slot 15 %d",
+ error);
+ return error;
+ }
+
+ /* DA_IN8 to AD_OUT6 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG,
+ SEL_AD_OUT6_FROM_DAIN8, 0);
+ if (0 != error) {
+ dev_err(dev, "Data sent to AD_OUT6 from DA_IN8 %d",
+ error);
+ return error;
+ }
+
+ initialVal = HW_REG_READ(AD_ALLOCATION_TO_SLOT16_17_REG);
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT16_17_REG,
+ (initialVal & MASK_QUARTET0)|SEL_IF17_FROM_AD_OUT6);
+ if (0 != error) {
+ dev_err(dev, "Data sent to IF17 from AD_OUT6 %d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+
+int ste_audio_io_power_down_fmtx(enum AUDIOIO_CH_INDEX channel_index,
+ struct device *dev)
+{
+ int error = 0;
+ unsigned char initialVal_AD = 0;
+
+ if (!(channel_index & (e_CHANNEL_1 | e_CHANNEL_2))) {
+ dev_err(dev, "FMTX should have mono or stereo channels");
+ return -EINVAL;
+ }
+
+ if (channel_index & e_CHANNEL_1) {
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA7_REG, 0,
+ SLOT14_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to DA_IN7 from Slot 14 %d",
+ error);
+ return error;
+ }
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA5_REG, 0,
+ SEL_AD_OUT5_FROM_DAIN7);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to AD_OUT5 from DA_IN7 %d",
+ error);
+ return error;
+ }
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT16_17_REG,
+ SEL_IF6_FROM_AD_OUT5);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to IF16 from AD_OUT8 %d",
+ error);
+ return error;
+ }
+ }
+
+ if (channel_index & e_CHANNEL_2) {
+ /* data sent to DA8 input of DA filter */
+ initialVal_AD = HW_REG_READ(SLOT_SELECTION_TO_DA8_REG);
+
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA8_REG, 0,
+ SLOT15_FOR_DA_PATH);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to DA_IN8 from Slot 15 %d",
+ error);
+ return error;
+ }
+
+ /* DA_IN7 to AD_OUT8 path */
+ error = HW_ACODEC_MODIFY_WRITE(SLOT_SELECTION_TO_DA6_REG, 0,
+ SEL_AD_OUT6_FROM_DAIN8);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to AD_OUT6 from DA_IN8 %d",
+ error);
+ return error;
+ }
+ error = HW_REG_WRITE(AD_ALLOCATION_TO_SLOT16_17_REG,
+ SEL_IF17_FROM_AD_OUT6);
+ if (0 != error) {
+ dev_err(dev,
+ "Clearing Data sent to IF17 from AD_OUT6 %d",
+ error);
+ return error;
+ }
+ }
+ return error;
+}
+int ste_audio_io_power_up_bluetooth(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev)
+{
+ int error = 0;
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+ struct ab8500_platform_data *pdata = dev_get_platdata(ab8500->dev);
+ if (bluetooth_power_up_count++)
+ return error;
+
+ if (pdata) {
+ if (pdata->audio) {
+ error = pdata->audio->ste_gpio_altf_init();
+ if (error == 0) {
+ clk_ptr_msp0 = clk_get_sys("msp0", NULL);
+ if (!IS_ERR(clk_ptr_msp0)) {
+ error = clk_enable(clk_ptr_msp0);
+ return error;
+ } else
+ return -EFAULT;
+ }
+ }
+ }
+ return error;
+}
+
+int ste_audio_io_power_down_bluetooth(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev)
+{
+ int error = 0;
+ struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+ struct ab8500_platform_data *pdata = dev_get_platdata(ab8500->dev);
+
+ if (--bluetooth_power_up_count)
+ return error;
+
+ if (pdata) {
+ if (pdata->audio) {
+ error = pdata->audio->ste_gpio_altf_exit();
+ if (error == 0) {
+ clk_disable(clk_ptr_msp0);
+ clk_put(clk_ptr_msp0);
+ }
+ }
+ }
+ return error;
+}
+
+int dump_acodec_registers(const char *str, struct device *dev)
+{
+ int reg_count = REVISION_REG & 0xff;
+ if (1 == acodec_reg_dump) {
+ u8 i = 0;
+ dev_info(dev, "\n func : %s\n", str);
+ for (i = 0; i <= reg_count; i++)
+ dev_info(dev,
+ "block = 0x0D, adr = %x = %x\n",
+ i, HW_REG_READ((AB8500_AUDIO << 8) | i));
+ }
+ str = str; /* keep compiler happy */
+ return 0;
+}
+
+int debug_audioio(int x)
+{
+
+ if (1 == x)
+ acodec_reg_dump = 1;
+ else
+ acodec_reg_dump = 0;
+ return 0;
+}
+
+
+
+
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_func.h b/drivers/misc/audio_io_dev/ste_audio_io_func.h
new file mode 100644
index 00000000000..282b25751d6
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_func.h
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#ifndef _AUDIOIO_FUNC_H_
+#define _AUDIOIO_FUNC_H_
+
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <mach/ste_audio_io_ioctl.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500.h>
+
+#define AB8500_REV_10 0x10
+#define AB8500_REV_11 0x11
+#define AB8500_REV_20 0x20
+
+#define AB8500_CTRL3_REG 0x00000200
+#define AB8500_SYSULPCLK_CTRL1_REG 0x0000020B
+#define AB8500_GPIO_DIR4_REG 0x00001013
+#define AB8500_GPIO_DIR5_REG 0x00001014
+#define AB8500_GPIO_OUT5_REG 0x00001024
+
+extern struct platform_device *ste_audio_io_device;
+extern struct regulator *regulator_avsource;
+
+int dump_acodec_registers(const char *, struct device *dev);
+int debug_audioio(int x);
+
+#define AB8500_BLOCK_ADDR(address) ((address >> 8) & 0xff)
+#define AB8500_OFFSET_ADDR(address) (address & 0xff)
+
+static inline unsigned char HW_REG_READ(unsigned short reg)
+{
+ unsigned char ret;
+ int err;
+
+ err = abx500_get_register_interruptible(&ste_audio_io_device->dev,
+ AB8500_BLOCK_ADDR(reg),
+ AB8500_OFFSET_ADDR(reg),
+ &ret);
+ if (err < 0)
+ return err;
+ else
+ return ret;
+}
+
+static inline int HW_REG_WRITE(unsigned short reg, unsigned char data)
+{
+ return abx500_set_register_interruptible(&ste_audio_io_device->dev,
+ AB8500_BLOCK_ADDR(reg),
+ AB8500_OFFSET_ADDR(reg),
+ data);
+}
+
+unsigned int ab8500_acodec_modify_write(unsigned int reg, u8 mask_set,
+ u8 mask_clear);
+
+#define HW_ACODEC_MODIFY_WRITE(reg, mask_set, mask_clear)\
+ ab8500_acodec_modify_write(reg, mask_set, mask_clear)
+
+unsigned int ab8500_modify_write(unsigned int reg, u8 mask_set, u8 mask_clear);
+
+int ste_audio_io_power_up_headset(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_headset(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_headset_query(struct device *dev);
+int ste_audio_io_set_headset_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_headset_gain(int *, int *, u16,
+ struct device *dev);
+int ste_audio_io_mute_headset(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_headset(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_headset_state(struct device *dev);
+int ste_audio_io_enable_fade_headset(struct device *dev);
+int ste_audio_io_disable_fade_headset(struct device *dev);
+int ste_audio_io_switch_to_burst_mode_headset(int burst_fifo_switch_frame,
+ struct device *dev);
+int ste_audio_io_switch_to_normal_mode_headset(
+ struct device *dev);
+
+int ste_audio_io_power_up_earpiece(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_earpiece(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_earpiece_query(struct device *dev);
+int ste_audio_io_set_earpiece_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_earpiece_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_earpiece(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_earpiece(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_earpiece_state(struct device *dev);
+int ste_audio_io_enable_fade_earpiece(struct device *dev);
+int ste_audio_io_disable_fade_earpiece(struct device *dev);
+
+int ste_audio_io_power_up_ihf(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_ihf(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_ihf_query(struct device *dev);
+int ste_audio_io_set_ihf_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_ihf_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_ihf(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_ihf(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_ihf_state(struct device *dev);
+int ste_audio_io_enable_fade_ihf(struct device *dev);
+int ste_audio_io_disable_fade_ihf(struct device *dev);
+
+int ste_audio_io_power_up_vibl(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_vibl(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_vibl_query(struct device *dev);
+int ste_audio_io_set_vibl_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_vibl_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_vibl(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_vibl(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_vibl_state(struct device *dev);
+int ste_audio_io_enable_fade_vibl(struct device *dev);
+int ste_audio_io_disable_fade_vibl(struct device *dev);
+
+int ste_audio_io_power_up_vibr(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_vibr(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_vibr_query(struct device *dev);
+int ste_audio_io_set_vibr_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_vibr_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_vibr(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_vibr(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_vibr_state(struct device *dev);
+int ste_audio_io_enable_fade_vibr(struct device *dev);
+int ste_audio_io_disable_fade_vibr(struct device *dev);
+
+int ste_audio_io_power_up_mic1a(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_mic1a(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_mic1a_query(struct device *dev);
+int ste_audio_io_set_mic1a_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear, struct device *dev);
+int ste_audio_io_get_mic1a_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_mic1a(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_mic1a(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_mic1a_state(struct device *dev);
+int ste_audio_io_enable_fade_mic1a(struct device *dev);
+int ste_audio_io_disable_fade_mic1a(struct device *dev);
+
+/*
+ *** Mic1b ***
+ */
+int ste_audio_io_power_up_mic1b(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_mic1b(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_mic1b_query(struct device *dev);
+int ste_audio_io_set_mic1b_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear, struct device *dev);
+int ste_audio_io_get_mic1b_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_mic1b(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_mic1b(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_mic1b_state(struct device *dev);
+int ste_audio_io_enable_fade_mic1b(struct device *dev);
+int ste_audio_io_disable_fade_mic1b(struct device *dev);
+int ste_audio_io_enable_loop_mic1b(enum AUDIOIO_CH_INDEX chnl_index,
+ enum AUDIOIO_HAL_HW_LOOPS,
+ int loop_gain, struct device *dev,
+ void *cookie);
+int ste_audio_io_disable_loop_mic1b(enum AUDIOIO_CH_INDEX chnl_index,
+ enum AUDIOIO_HAL_HW_LOOPS hw_loop,
+ struct device *dev, void *cookie);
+/*
+ *** Mic2 ***
+ */
+int ste_audio_io_power_up_mic2(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_mic2(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_mic2_query(struct device *dev);
+int ste_audio_io_set_mic2_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_mic2_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_mic2(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_mic2(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_mic2_state(struct device *dev);
+int ste_audio_io_enable_fade_mic2(struct device *dev);
+int ste_audio_io_disable_fade_mic2(struct device *dev);
+
+int ste_audio_io_power_up_lin(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_lin(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_lin_query(struct device *dev);
+int ste_audio_io_set_lin_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_lin_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_lin(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_lin(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_lin_state(struct device *dev);
+int ste_audio_io_enable_fade_lin(struct device *dev);
+int ste_audio_io_disable_fade_lin(struct device *dev);
+
+int ste_audio_io_power_up_dmic12(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_dmic12(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_dmic12_query(struct device *dev);
+int ste_audio_io_set_dmic12_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_dmic12_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_dmic12(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_dmic12(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_dmic12_state(struct device *dev);
+int ste_audio_io_enable_fade_dmic12(struct device *dev);
+int ste_audio_io_disable_fade_dmic12(struct device *dev);
+int ste_audio_io_enable_loop_dmic12(enum AUDIOIO_CH_INDEX chnl_index,
+ enum AUDIOIO_HAL_HW_LOOPS,
+ int loop_gain, struct device *dev,
+ void *cookie);
+int ste_audio_io_disable_loop_dmic12(enum AUDIOIO_CH_INDEX chnl_index,
+ enum AUDIOIO_HAL_HW_LOOPS hw_loop,
+ struct device *dev, void *cookie);
+
+int ste_audio_io_power_up_dmic34(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_dmic34(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_dmic34_query(struct device *dev);
+int ste_audio_io_set_dmic34_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_dmic34_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_dmic34(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_dmic34(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_dmic34_state(struct device *dev);
+int ste_audio_io_enable_fade_dmic34(struct device *dev);
+int ste_audio_io_disable_fade_dmic34(struct device *dev);
+
+int ste_audio_io_power_up_dmic56(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_dmic56(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_dmic56_query(struct device *dev);
+int ste_audio_io_set_dmic56_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_dmic56_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_dmic56(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_dmic56(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_dmic56_state(struct device *dev);
+int ste_audio_io_enable_fade_dmic56(struct device *dev);
+int ste_audio_io_disable_fade_dmic56(struct device *dev);
+
+int ste_audio_io_power_up_fmrx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_fmrx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_fmrx_query(struct device *dev);
+int ste_audio_io_set_fmrx_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_fmrx_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_fmrx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_fmrx(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_fmrx_state(struct device *dev);
+int ste_audio_io_enable_fade_fmrx(struct device *dev);
+int ste_audio_io_disable_fade_fmrx(struct device *dev);
+
+int ste_audio_io_power_up_fmtx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_fmtx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_fmtx_query(struct device *dev);
+int ste_audio_io_set_fmtx_gain(enum AUDIOIO_CH_INDEX chnl_index, u16 gain_index,
+ int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_fmtx_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_fmtx(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_fmtx(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_fmtx_state(struct device *dev);
+int ste_audio_io_enable_fade_fmtx(struct device *dev);
+int ste_audio_io_disable_fade_fmtx(struct device *dev);
+
+int ste_audio_io_power_up_bluetooth(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_down_bluetooth(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_power_state_bluetooth_query(struct device *dev);
+int ste_audio_io_set_bluetooth_gain(enum AUDIOIO_CH_INDEX chnl_index,
+ u16 gain_index, int gain_value, u32 linear,
+ struct device *dev);
+int ste_audio_io_get_bluetooth_gain(int*, int*, u16,
+ struct device *dev);
+int ste_audio_io_mute_bluetooth(enum AUDIOIO_CH_INDEX chnl_index,
+ struct device *dev);
+int ste_audio_io_unmute_bluetooth(enum AUDIOIO_CH_INDEX chnl_index, int *gain,
+ struct device *dev);
+int ste_audio_io_mute_bluetooth_state(struct device *dev);
+int ste_audio_io_enable_fade_bluetooth(struct device *dev);
+int ste_audio_io_disable_fade_bluetooth(struct device *dev);
+
+
+#endif
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.c b/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.c
new file mode 100644
index 00000000000..c2409f849ae
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+
+#include <linux/types.h>
+#include "ste_audio_io_hwctrl_common.h"
+
+/* Number of channels for each transducer */
+const uint transducer_no_of_channels[MAX_NO_TRANSDUCERS] = {
+ 1, /* Earpiece */
+ 2, /* HS */
+ 2, /* IHF */
+ 1, /* VibL */
+ 1, /* VibR */
+ 1, /* Mic1A */
+ 1, /* Mic1B */
+ 1, /* Mic2 */
+ 2, /* LinIn */
+ 2, /* DMIC12 */
+ 2, /* DMIC34 */
+ 2, /* /DMIC56 */
+ 4 /* MultiMic */
+ };
+
+/* Maximum number of gains in each transducer path
+ (all channels of a specific transducer have same max no of gains) */
+const uint transducer_no_of_gains[MAX_NO_TRANSDUCERS] = {
+ 2, /* Ear g3 and g4 */
+ 3, /* HS g3 and g4 and analog */
+ 1, /* IHF g3 */
+ 1, /* VibL g3 */
+ 1, /* VibR g3 */
+ 2, /* Mic1A g1 and analog */
+ 2, /* Mic1A g1 and analog */
+ 2, /* Mic2 g1 and analog */
+ 2, /* LinIn g1 and analog */
+ 1, /* DMIC12 g1 */
+ 1, /* DMIC34 g1 */
+ 1, /* DMIC56 g1 */
+ 1 /* MultiMic g1 */
+ };
+
+const uint transducer_no_Of_supported_loop_indexes[MAX_NO_TRANSDUCERS] = {
+ 0x09,/* Ear0x01|0x08*/
+ 0x38770,/*{0x01|0x10|0x20|0x40|0x100*/
+ /*|0x200|0x400|0x8000|0x10000|0x20000}, HS*/
+ 0x86,/*IHF*/
+ 0x0,/*VibL*/
+ 0x0,/*VibR*/
+ 0x0,/*Mic1A*/
+ 0x01,/*Mic1B Sidetone is controlled*/
+ 0x0,/*Mic2*/
+ 0x0,/*LinIn*/
+ 0x0,/*DMIC12*/
+ 0x0,/*DMIC34*/
+ 0x0,/*DMIC56*/
+ 0x01,/*MultiMic Sidetone is controlled*/
+ 0x0,/*FMRx*/
+ 0x0/*FMTx*/
+ };
+
+const uint transducer_max_no_Of_supported_loops[MAX_NO_TRANSDUCERS] = {
+ 0,/*Ear Sidetone*/
+ 2,/*HS SideTone LININ_HS LININR_HSR LININ_HSL*/
+ 1,/*IHF TO BE DEFINED*/
+ 0,/*VibL TO BE DEFINED*/
+ 0,/*VibR TO BE DEFINED*/
+ 1,/*Mic1A TO BE DEFINED*/
+ 1,/*Mic1B SIDETONE TO BE DEFINED*/
+ 1,/*Mic2 TO BE DEFINED*/
+ 0, /* LinIn */
+ 1,/*DMIC12-ANC*/
+ 0,/*DMIC34-ANC*/
+ 0, /* DMIC56 */
+ 1,/*MultiMic-SIDETONE ANC*/
+ 0,/*FMRx*/
+ 0/*FMTx*/
+ };
+
+const uint max_no_of_loop_gains[MAX_NO_TRANSDUCERS] = {
+ 0,/*Earpiece*/
+ 2,/*HS*/
+ 0,
+ 0,
+ 0,
+ 0,
+ 2,/*Mic1B-Sidetone 2 gains*/
+ 0,
+ 0,
+ 2,/*DMIC12*/
+ 0,
+ 0,
+ 2,/*Multimic, Sidetone max no gains = 2*/
+ 0,
+ 0
+ };
+
+
+struct gain_descriptor_t gain_descriptor[MAX_NO_TRANSDUCERS]\
+ [MAX_NO_CHANNELS][MAX_NO_GAINS] = {
+ /* gainIndex=0 1 2
+ EDestinationEar */
+ {{{-63, 0, 1}, {-1, 8, 1}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* EDestinationHS */
+ {{{-63, 0, 1}, {-1, 8, 1}, {-32, 4, 2} } , /* channelIndex=0 */
+ {{-63, 0, 1}, {-1, 8, 1}, {-32, 4, 2} } , /* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } , /* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } , /* channelIndex=3 */
+
+ /* EDestinationIHF */
+ {{{-63, 0, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-63, 0, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* EDestinationVibL */
+ {{{-63, 0, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* EDestinationVibR */
+ {{{-63, 0, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceMic1A */
+ {{{-32, 31, 1}, {0, 31, 1}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceMic1B */
+ {{{-32, 31, 1}, {0, 31, 1}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceMic2 */
+ {{{-32, 31, 1}, {0, 31, 1}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceLin */
+ {{{-32, 31, 1}, {-10, 20, 2}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-32, 31, 1}, {-10, 20, 2}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceDMic12 */
+ {{{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceDMic34 */
+ {{{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceDMic56 */
+ {{{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=2 */
+ {{0, 0, 0}, {0, 0, 0}, {0, 0, 0} } } ,/* channelIndex=3 */
+
+ /* ESourceMultiMic */
+ {{{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=0 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } ,/* channelIndex=1 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} },/* channelIndex=2 */
+ {{-32, 31, 1}, {0, 0, 0}, {0, 0, 0} } } /* channelIndex=3 */
+};
+
+
+const int hs_analog_gain_table[16] = {4, 2, 0, -2, -4, -6, -8, -10,
+ -12, -14, -16, -18, -20, -24, -28, -32};
+
+
+
diff --git a/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.h b/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.h
new file mode 100644
index 00000000000..cc2bfe21d81
--- /dev/null
+++ b/drivers/misc/audio_io_dev/ste_audio_io_hwctrl_common.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Deepak KARDA/ deepak.karda@stericsson.com for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#ifndef __AUDIOIO_HWCTRL_COMMON_H__
+#define __AUDIOIO_HWCTRL_COMMON_H__
+
+#include <linux/types.h>
+#include <mach/ste_audio_io_ioctl.h>
+/*
+ * Defines
+ */
+
+#define MAX_GAIN 100
+#define MIN_GAIN 0
+#define MAX_NO_CHANNELS 4
+#define MAX_NO_GAINS 3
+#define MAX_NO_LOOPS 1
+#define MAX_NO_LOOP_GAINS 1
+
+struct gain_descriptor_t {
+ int min_gain;
+ int max_gain;
+ uint gain_step;
+};
+
+
+/* Number of channels for each transducer */
+extern const uint transducer_no_of_channels[MAX_NO_TRANSDUCERS];
+
+/*
+ * Maximum number of gains in each transducer path
+ * all channels of a specific transducer have same max no of gains
+ */
+extern const uint transducer_no_of_gains[MAX_NO_TRANSDUCERS];
+
+/* Maximum number of supported loops for each transducer */
+extern const uint transducer_no_Of_supported_loop_indexes[MAX_NO_TRANSDUCERS];
+extern const uint transducer_max_no_Of_supported_loops[MAX_NO_TRANSDUCERS];
+extern const uint max_no_of_loop_gains[MAX_NO_TRANSDUCERS];
+extern const int hs_analog_gain_table[16] ;
+
+extern struct gain_descriptor_t gain_descriptor[MAX_NO_TRANSDUCERS]\
+ [MAX_NO_CHANNELS][MAX_NO_GAINS];
+
+#endif
+
+/* End of audio_io_hwctrl_common.h */