aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/intel_sst
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-23 12:49:28 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-23 12:49:28 -0700
commit1f3a8e093f470ef193b0ca6011d90180331c8b53 (patch)
tree66b7a58decabdc7f76ffb102899881c258c1df59 /drivers/staging/intel_sst
parentc44dead70a841d90ddc01968012f323c33217c9e (diff)
parent1a4b6f66285785ddccef049e6b45be4e7c7a2189 (diff)
downloadkernel_samsung_smdk4412-1f3a8e093f470ef193b0ca6011d90180331c8b53.zip
kernel_samsung_smdk4412-1f3a8e093f470ef193b0ca6011d90180331c8b53.tar.gz
kernel_samsung_smdk4412-1f3a8e093f470ef193b0ca6011d90180331c8b53.tar.bz2
Merge branch 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
* 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6: (970 commits) staging: usbip: replace usbip_u{dbg,err,info} and printk with dev_ and pr_ staging:iio: Trivial kconfig reorganization and uniformity improvements. staging:iio:documenation partial update. staging:iio: use pollfunc allocation helpers in remaining drivers. staging:iio:max1363 misc cleanups and use of for_each_bit_set to simplify event code spitting out. staging:iio: implement an iio_info structure to take some of the constant elements out of iio_dev. staging:iio:meter:ade7758: Use private data space from iio_allocate_device staging:iio:accel:lis3l02dq make write_reg_8 take value not a pointer to value. staging:iio: ring core cleanups + check if read_last available in lis3l02dq staging:iio:core cleanup: squash tiny wrappers and use dev_set_name to handle creation of event interface name. staging:iio: poll func allocation clean up. staging:iio:ad7780 trivial unused header cleanup. staging:iio:adc: AD7780: Use private data space from iio_allocate_device + trivial fixes staging:iio:adc:AD7780: Convert to new channel registration method staging:iio:adc: AD7606: Drop dev_data in favour of iio_priv() staging:iio:adc: AD7606: Consitently use indio_dev staging:iio: Rip out helper for software rings. staging:iio:adc:AD7298: Use private data space from iio_allocate_device staging:iio: rationalization of different buffer implementation hooks. staging:iio:imu:adis16400 avoid allocating rx, tx, and state separately from iio_dev. ... Fix up trivial conflicts in - drivers/staging/intel_sst/intelmid.c: patches applied in both branches - drivers/staging/rt2860/common/cmm_data_{pci,usb}.c: removed vs spelling - drivers/staging/usbip/vhci_sysfs.c: trivial header file inclusion
Diffstat (limited to 'drivers/staging/intel_sst')
-rw-r--r--drivers/staging/intel_sst/intel_sst.c129
-rw-r--r--drivers/staging/intel_sst/intel_sst.h33
-rw-r--r--drivers/staging/intel_sst/intel_sst_app_interface.c45
-rw-r--r--drivers/staging/intel_sst/intel_sst_common.h9
-rw-r--r--drivers/staging/intel_sst/intel_sst_drv_interface.c24
-rw-r--r--drivers/staging/intel_sst/intel_sst_dsp.c14
-rw-r--r--drivers/staging/intel_sst/intel_sst_fw_ipc.h7
-rw-r--r--drivers/staging/intel_sst/intel_sst_ioctl.h8
-rw-r--r--drivers/staging/intel_sst/intel_sst_ipc.c74
-rw-r--r--drivers/staging/intel_sst/intel_sst_pvt.c2
-rw-r--r--drivers/staging/intel_sst/intel_sst_stream.c15
-rw-r--r--drivers/staging/intel_sst/intel_sst_stream_encoded.c8
-rw-r--r--drivers/staging/intel_sst/intelmid.c473
-rw-r--r--drivers/staging/intel_sst/intelmid.h38
-rw-r--r--drivers/staging/intel_sst/intelmid_adc_control.h193
-rw-r--r--drivers/staging/intel_sst/intelmid_ctrl.c304
-rw-r--r--drivers/staging/intel_sst/intelmid_msic_control.c833
-rw-r--r--drivers/staging/intel_sst/intelmid_pvt.c1
-rw-r--r--drivers/staging/intel_sst/intelmid_snd_control.h9
-rw-r--r--drivers/staging/intel_sst/intelmid_v0_control.c109
-rw-r--r--drivers/staging/intel_sst/intelmid_v1_control.c141
-rw-r--r--drivers/staging/intel_sst/intelmid_v2_control.c219
-rw-r--r--drivers/staging/intel_sst/jack.h10
23 files changed, 2131 insertions, 567 deletions
diff --git a/drivers/staging/intel_sst/intel_sst.c b/drivers/staging/intel_sst/intel_sst.c
index 81c24d1..c0c144a 100644
--- a/drivers/staging/intel_sst/intel_sst.c
+++ b/drivers/staging/intel_sst/intel_sst.c
@@ -107,6 +107,9 @@ static irqreturn_t intel_sst_interrupt(int irq, void *context)
unsigned int size = 0, str_id;
struct stream_info *stream ;
+ /* Do not handle interrupt in suspended state */
+ if (drv->sst_state == SST_SUSPENDED)
+ return IRQ_NONE;
/* Interrupt arrived, check src */
isr.full = sst_shim_read(drv->shim, SST_ISRX);
@@ -316,14 +319,30 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
ret = misc_register(&lpe_dev);
if (ret) {
- pr_err("couldn't register misc driver\n");
+ pr_err("couldn't register LPE device\n");
goto do_free_misc;
}
+ } else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) {
+ u32 csr;
+
+ /*allocate mem for fw context save during suspend*/
+ sst_drv_ctx->fw_cntx = kzalloc(FW_CONTEXT_MEM, GFP_KERNEL);
+ if (!sst_drv_ctx->fw_cntx) {
+ ret = -ENOMEM;
+ goto do_free_misc;
+ }
+ /*setting zero as that is valid mem to restore*/
+ sst_drv_ctx->fw_cntx_size = 0;
+
+ /*set lpe start clock and ram size*/
+ csr = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr |= 0x30060; /*remove the clock ratio after fw fix*/
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr);
}
sst_drv_ctx->lpe_stalled = 0;
- pm_runtime_set_active(&pci->dev);
- pm_runtime_enable(&pci->dev);
+ pci_set_drvdata(pci, sst_drv_ctx);
pm_runtime_allow(&pci->dev);
+ pm_runtime_put_noidle(&pci->dev);
pr_debug("...successfully done!!!\n");
return ret;
@@ -355,7 +374,8 @@ free_mad_wq:
destroy_workqueue(sst_drv_ctx->mad_wq);
do_free_drv_ctx:
kfree(sst_drv_ctx);
- pr_err("Probe failed with 0x%x\n", ret);
+ sst_drv_ctx = NULL;
+ pr_err("Probe failed with %d\n", ret);
return ret;
}
@@ -369,35 +389,76 @@ do_free_drv_ctx:
*/
static void __devexit intel_sst_remove(struct pci_dev *pci)
{
+ pm_runtime_get_noresume(&pci->dev);
+ pm_runtime_forbid(&pci->dev);
pci_dev_put(sst_drv_ctx->pci);
mutex_lock(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = SST_UN_INIT;
mutex_unlock(&sst_drv_ctx->sst_lock);
misc_deregister(&lpe_ctrl);
- if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
- misc_deregister(&lpe_dev);
free_irq(pci->irq, sst_drv_ctx);
iounmap(sst_drv_ctx->dram);
iounmap(sst_drv_ctx->iram);
iounmap(sst_drv_ctx->mailbox);
iounmap(sst_drv_ctx->shim);
sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
- if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
+ misc_deregister(&lpe_dev);
kfree(sst_drv_ctx->mmap_mem);
+ } else
+ kfree(sst_drv_ctx->fw_cntx);
flush_scheduled_work();
destroy_workqueue(sst_drv_ctx->process_reply_wq);
destroy_workqueue(sst_drv_ctx->process_msg_wq);
destroy_workqueue(sst_drv_ctx->post_msg_wq);
destroy_workqueue(sst_drv_ctx->mad_wq);
- kfree(sst_drv_ctx);
- pci_release_region(pci, 1);
- pci_release_region(pci, 2);
- pci_release_region(pci, 3);
- pci_release_region(pci, 4);
- pci_release_region(pci, 5);
+ kfree(pci_get_drvdata(pci));
+ sst_drv_ctx = NULL;
+ pci_release_regions(pci);
+ pci_disable_device(pci);
pci_set_drvdata(pci, NULL);
}
+void sst_save_dsp_context(void)
+{
+ struct snd_sst_ctxt_params fw_context;
+ unsigned int pvt_id, i;
+ struct ipc_post *msg = NULL;
+
+ /*check cpu type*/
+ if (sst_drv_ctx->pci_id != SST_MFLD_PCI_ID)
+ return;
+ /*not supported for rest*/
+ if (sst_drv_ctx->sst_state != SST_FW_RUNNING) {
+ pr_debug("fw not running no context save ...\n");
+ return;
+ }
+
+ /*send msg to fw*/
+ if (sst_create_large_msg(&msg))
+ return;
+ pvt_id = sst_assign_pvt_id(sst_drv_ctx);
+ i = sst_get_block_stream(sst_drv_ctx);
+ sst_drv_ctx->alloc_block[i].sst_id = pvt_id;
+ sst_fill_header(&msg->header, IPC_IA_GET_FW_CTXT, 1, pvt_id);
+ msg->header.part.data = sizeof(fw_context) + sizeof(u32);
+ fw_context.address = virt_to_phys((void *)sst_drv_ctx->fw_cntx);
+ fw_context.size = FW_CONTEXT_MEM;
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32),
+ &fw_context, sizeof(fw_context));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ /*wait for reply*/
+ if (sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]))
+ pr_debug("err fw context save timeout ...\n");
+ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+ pr_debug("fw context saved ...\n");
+ return;
+}
+
/* Power Management */
/*
* intel_sst_suspend - PCI suspend function
@@ -417,6 +478,8 @@ int intel_sst_suspend(struct pci_dev *pci, pm_message_t state)
pr_err("active streams,not able to suspend\n");
return -EBUSY;
}
+ /*save fw context*/
+ sst_save_dsp_context();
/*Assert RESET on LPE Processor*/
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.full = csr.full | 0x2;
@@ -461,18 +524,45 @@ int intel_sst_resume(struct pci_dev *pci)
return 0;
}
+/* The runtime_suspend/resume is pretty much similar to the legacy suspend/resume with the noted exception below:
+ * The PCI core takes care of taking the system through D3hot and restoring it back to D0 and so there is
+ * no need to duplicate that here.
+ */
static int intel_sst_runtime_suspend(struct device *dev)
{
- struct pci_dev *pci_dev = to_pci_dev(dev);
- pr_debug("runtime_suspend called\n");
- return intel_sst_suspend(pci_dev, PMSG_SUSPEND);
+ union config_status_reg csr;
+
+ pr_debug("intel_sst_runtime_suspend called\n");
+ if (sst_drv_ctx->stream_cnt) {
+ pr_err("active streams,not able to suspend\n");
+ return -EBUSY;
+ }
+ /*save fw context*/
+ sst_save_dsp_context();
+ /*Assert RESET on LPE Processor*/
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.full = csr.full | 0x2;
+ /* Move the SST state to Suspended */
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_SUSPENDED;
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ return 0;
}
static int intel_sst_runtime_resume(struct device *dev)
{
- struct pci_dev *pci_dev = to_pci_dev(dev);
- pr_debug("runtime_resume called\n");
- return intel_sst_resume(pci_dev);
+
+ pr_debug("intel_sst_runtime_resume called\n");
+ if (sst_drv_ctx->sst_state != SST_SUSPENDED) {
+ pr_err("SST is not in suspended state\n");
+ return 0;
+ }
+
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = SST_UN_INIT;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ return 0;
}
static int intel_sst_runtime_idle(struct device *dev)
@@ -545,6 +635,7 @@ static void __exit intel_sst_exit(void)
pci_unregister_driver(&driver);
pr_debug("driver unloaded\n");
+ sst_drv_ctx = NULL;
return;
}
diff --git a/drivers/staging/intel_sst/intel_sst.h b/drivers/staging/intel_sst/intel_sst.h
index cb03ff7..4ad2829 100644
--- a/drivers/staging/intel_sst/intel_sst.h
+++ b/drivers/staging/intel_sst/intel_sst.h
@@ -30,9 +30,11 @@
* This file is shared between the SST and MAD drivers
*/
#include "intel_sst_ioctl.h"
+#include <sound/jack.h>
#define SST_CARD_NAMES "intel_mid_card"
+#define MFLD_MAX_HW_CH 4
/* control list Pmic & Lpe */
/* Input controls */
enum port_status {
@@ -82,12 +84,16 @@ struct snd_pmic_ops {
int num_channel;
int input_dev_id;
int mute_status;
- int pb_on;
+ struct mutex lock;
+ int pb_on, pbhs_on;
int cap_on;
int output_dev_id;
+ int lineout_dev_id, line_out_names_cnt;
+ int prev_lineout_dev_id;
+ bool jack_interrupt_status;
int (*set_input_dev) (u8 value);
int (*set_output_dev) (u8 value);
-
+ int (*set_lineout_dev) (u8 value);
int (*set_mute) (int dev_id, u8 value);
int (*get_mute) (int dev_id, u8 *value);
@@ -103,11 +109,30 @@ struct snd_pmic_ops {
int (*power_up_pmic_pb) (unsigned int port);
int (*power_up_pmic_cp) (unsigned int port);
- int (*power_down_pmic_pb) (void);
- int (*power_down_pmic_cp) (void);
+ int (*power_down_pmic_pb) (unsigned int device);
+ int (*power_down_pmic_cp) (unsigned int device);
int (*power_down_pmic) (void);
+ void (*pmic_irq_cb) (void *cb_data, u8 value);
+ void (*pmic_irq_enable)(void *data);
+ int (*pmic_jack_enable) (void);
+ int (*pmic_get_mic_bias)(void *intelmaddata);
+ int (*pmic_set_headset_state)(int state);
+
+ unsigned int hw_dmic_map[MFLD_MAX_HW_CH];
+ unsigned int available_dmics;
+ int (*set_hw_dmic_route) (u8 index);
+
+ int gpio_amp;
};
+extern void sst_mad_send_jack_report(struct snd_jack *jack,
+ int buttonpressevent,
+ int status);
+
+
+int intemad_set_headset_state(int state);
+int intelmad_get_mic_bias(void);
+
struct intel_sst_pcm_control {
int (*open) (struct snd_sst_params *str_param);
int (*device_control) (int cmd, void *arg);
diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c
index 1d06212..b8c7ddb 100644
--- a/drivers/staging/intel_sst/intel_sst_app_interface.c
+++ b/drivers/staging/intel_sst/intel_sst_app_interface.c
@@ -418,10 +418,6 @@ static int snd_sst_fill_kernel_list(struct stream_info *stream,
static int sent_offset;
static unsigned long sent_index;
- stream_bufs = kzalloc(sizeof(*stream_bufs), GFP_KERNEL);
- if (!stream_bufs)
- return -ENOMEM;
- stream_bufs->addr = sst_drv_ctx->mmap_mem;
#ifdef CONFIG_MRST_RAR_HANDLER
if (stream->ops == STREAM_OPS_PLAYBACK_DRM) {
for (index = stream->sg_index; index < nr_segs; index++) {
@@ -448,6 +444,10 @@ static int snd_sst_fill_kernel_list(struct stream_info *stream,
return retval;
}
#endif
+ stream_bufs = kzalloc(sizeof(*stream_bufs), GFP_KERNEL);
+ if (!stream_bufs)
+ return -ENOMEM;
+ stream_bufs->addr = sst_drv_ctx->mmap_mem;
mmap_len = sst_drv_ctx->mmap_len;
stream_bufs->addr = sst_drv_ctx->mmap_mem;
bufp = stream->cur_ptr;
@@ -961,6 +961,34 @@ free_mem:
return retval;
}
+
+int sst_ioctl_tuning_params(unsigned long arg)
+{
+ struct snd_sst_tuning_params params;
+ struct ipc_post *msg;
+
+ if (copy_from_user(&params, (void __user *)arg, sizeof(params)))
+ return -EFAULT;
+ if (params.size > SST_MAILBOX_SIZE)
+ return -ENOMEM;
+ pr_debug("Parameter %d, Stream %d, Size %d\n", params.type,
+ params.str_id, params.size);
+ if (sst_create_large_msg(&msg))
+ return -ENOMEM;
+
+ sst_fill_header(&msg->header, IPC_IA_TUNING_PARAMS, 1, params.str_id);
+ msg->header.part.data = sizeof(u32) + sizeof(params) + params.size;
+ memcpy(msg->mailbox_data, &msg->header.full, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32), &params, sizeof(params));
+ if (copy_from_user(msg->mailbox_data + sizeof(params),
+ (void __user *)(unsigned long)params.addr,
+ params.size)) {
+ kfree(msg->mailbox_data);
+ kfree(msg);
+ return -EFAULT;
+ }
+ return sst_send_algo_ipc(&msg);
+}
/**
* intel_sst_ioctl - receives the device ioctl's
* @file_ptr:pointer to file
@@ -1412,6 +1440,15 @@ free_iobufs:
}
retval = intel_sst_ioctl_dsp(cmd, arg);
break;
+
+ case _IOC_NR(SNDRV_SST_TUNING_PARAMS):
+ if (minor != AM_MODULE) {
+ retval = -EBADRQC;
+ break;
+ }
+ retval = sst_ioctl_tuning_params(arg);
+ break;
+
default:
retval = -EINVAL;
}
diff --git a/drivers/staging/intel_sst/intel_sst_common.h b/drivers/staging/intel_sst/intel_sst_common.h
index 0a60e86..f8e9da6 100644
--- a/drivers/staging/intel_sst/intel_sst_common.h
+++ b/drivers/staging/intel_sst/intel_sst_common.h
@@ -28,8 +28,8 @@
* Common private declarations for SST
*/
-#define SST_DRIVER_VERSION "1.2.09"
-#define SST_VERSION_NUM 0x1209
+#define SST_DRIVER_VERSION "1.2.17"
+#define SST_VERSION_NUM 0x1217
/* driver names */
#define SST_DRV_NAME "intel_sst_driver"
@@ -37,6 +37,7 @@
#define SST_MFLD_PCI_ID 0x082F
#define PCI_ID_LENGTH 4
#define SST_SUSPEND_DELAY 2000
+#define FW_CONTEXT_MEM (64*1024)
enum sst_states {
SST_FW_LOADED = 1,
@@ -94,7 +95,7 @@ enum sst_ram_type {
/* SST shim registers to structure mapping */
union config_status_reg {
struct {
- u32 rsvd0:1;
+ u32 mfld_strb:1;
u32 sst_reset:1;
u32 hw_rsvd:3;
u32 sst_clk:2;
@@ -417,6 +418,8 @@ struct intel_sst_drv {
unsigned int audio_start;
dev_t devt_d, devt_c;
unsigned int max_streams;
+ unsigned int *fw_cntx;
+ unsigned int fw_cntx_size;
};
extern struct intel_sst_drv *sst_drv_ctx;
diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c
index 971588c..1021477 100644
--- a/drivers/staging/intel_sst/intel_sst_drv_interface.c
+++ b/drivers/staging/intel_sst/intel_sst_drv_interface.c
@@ -105,21 +105,28 @@ void free_stream_context(unsigned int str_id)
if (!sst_validate_strid(str_id)) {
/* str_id is valid, so stream is alloacted */
stream = &sst_drv_ctx->streams[str_id];
+ if (sst_free_stream(str_id))
+ sst_clean_stream(&sst_drv_ctx->streams[str_id]);
if (stream->ops == STREAM_OPS_PLAYBACK ||
stream->ops == STREAM_OPS_PLAYBACK_DRM) {
sst_drv_ctx->pb_streams--;
- if (sst_drv_ctx->pb_streams == 0)
- sst_drv_ctx->scard_ops->power_down_pmic_pb();
+ if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID)
+ sst_drv_ctx->scard_ops->power_down_pmic_pb(
+ stream->device);
+ else {
+ if (sst_drv_ctx->pb_streams == 0)
+ sst_drv_ctx->scard_ops->
+ power_down_pmic_pb(stream->device);
+ }
} else if (stream->ops == STREAM_OPS_CAPTURE) {
sst_drv_ctx->cp_streams--;
if (sst_drv_ctx->cp_streams == 0)
- sst_drv_ctx->scard_ops->power_down_pmic_cp();
+ sst_drv_ctx->scard_ops->power_down_pmic_cp(
+ stream->device);
}
if (sst_drv_ctx->pb_streams == 0
&& sst_drv_ctx->cp_streams == 0)
sst_drv_ctx->scard_ops->power_down_pmic();
- if (sst_free_stream(str_id))
- sst_clean_stream(&sst_drv_ctx->streams[str_id]);
}
}
@@ -276,8 +283,8 @@ void sst_process_mad_ops(struct work_struct *work)
retval = sst_resume_stream(mad_ops->stream_id);
break;
case SST_SND_DROP:
-/* retval = sst_drop_stream(mad_ops->stream_id);
-*/ break;
+ retval = sst_drop_stream(mad_ops->stream_id);
+ break;
case SST_SND_START:
pr_debug("SST Debug: start stream\n");
retval = sst_start_stream(mad_ops->stream_id);
@@ -519,6 +526,9 @@ int register_sst_card(struct intel_sst_card_ops *card)
pr_err("Repeat for registration..denied\n");
return -EBADRQC;
}
+ /* The ASoC code doesn't set scard_ops */
+ if (sst_drv_ctx->scard_ops)
+ sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
return 0;
}
EXPORT_SYMBOL_GPL(register_sst_card);
diff --git a/drivers/staging/intel_sst/intel_sst_dsp.c b/drivers/staging/intel_sst/intel_sst_dsp.c
index bffe4c6..a89e1ad 100644
--- a/drivers/staging/intel_sst/intel_sst_dsp.c
+++ b/drivers/staging/intel_sst/intel_sst_dsp.c
@@ -73,7 +73,8 @@ static int intel_sst_reset_dsp_medfield(void)
union config_status_reg csr;
pr_debug("Resetting the DSP in medfield\n");
- csr.full = 0x048303E2;
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.full |= 0x382;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
return 0;
@@ -109,11 +110,16 @@ static int sst_start_medfield(void)
{
union config_status_reg csr;
- csr.full = 0x04830062;
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.bypass = 0;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
- csr.full = 0x04830063;
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.mfld_strb = 1;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
- csr.full = 0x04830061;
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.run_stall = 0;
+ csr.part.sst_reset = 0;
+ pr_debug("Starting the DSP_medfld %x\n", csr.full);
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
pr_debug("Starting the DSP_medfld\n");
diff --git a/drivers/staging/intel_sst/intel_sst_fw_ipc.h b/drivers/staging/intel_sst/intel_sst_fw_ipc.h
index 0f0c5bb..5d0cc56 100644
--- a/drivers/staging/intel_sst/intel_sst_fw_ipc.h
+++ b/drivers/staging/intel_sst/intel_sst_fw_ipc.h
@@ -56,6 +56,8 @@
#define IPC_IA_GET_FW_VERSION 0x04
#define IPC_IA_GET_FW_BUILD_INF 0x05
#define IPC_IA_GET_FW_INFO 0x06
+#define IPC_IA_GET_FW_CTXT 0x07
+#define IPC_IA_SET_FW_CTXT 0x08
/* I2L Codec Config/control msgs */
#define IPC_IA_SET_CODEC_PARAMS 0x10
@@ -69,6 +71,7 @@
#define IPC_IA_DECODE_FRAMES 0x18
#define IPC_IA_ALG_PARAMS 0x1A
+#define IPC_IA_TUNING_PARAMS 0x1B
/* I2L Stream config/control msgs */
#define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */
@@ -406,4 +409,8 @@ struct ipc_post {
char *mailbox_data;
};
+struct snd_sst_ctxt_params {
+ u32 address; /* Physical Address in DDR where the context is stored */
+ u32 size; /* size of the context */
+};
#endif /* __INTEL_SST_FW_IPC_H__ */
diff --git a/drivers/staging/intel_sst/intel_sst_ioctl.h b/drivers/staging/intel_sst/intel_sst_ioctl.h
index bebc395..5da5ee0 100644
--- a/drivers/staging/intel_sst/intel_sst_ioctl.h
+++ b/drivers/staging/intel_sst/intel_sst_ioctl.h
@@ -400,6 +400,13 @@ struct snd_sst_dbufs {
struct snd_sst_buffs *obufs;
};
+struct snd_sst_tuning_params {
+ __u8 type;
+ __u8 str_id;
+ __u8 size;
+ __u8 rsvd;
+ __aligned_u64 addr;
+} __attribute__ ((packed));
/*IOCTL defined here */
/*SST MMF IOCTLS only */
#define SNDRV_SST_STREAM_SET_PARAMS _IOR('L', 0x00, \
@@ -428,5 +435,6 @@ struct snd_sst_dbufs {
/*DSP Ioctls on /dev/intel_sst_ctrl only*/
#define SNDRV_SST_SET_ALGO _IOW('L', 0x30, struct snd_ppp_params *)
#define SNDRV_SST_GET_ALGO _IOWR('L', 0x31, struct snd_ppp_params *)
+#define SNDRV_SST_TUNING_PARAMS _IOW('L', 0x32, struct snd_sst_tuning_params *)
#endif /* __INTEL_SST_IOCTL_H__ */
diff --git a/drivers/staging/intel_sst/intel_sst_ipc.c b/drivers/staging/intel_sst/intel_sst_ipc.c
index 0742dde..5c3444f 100644
--- a/drivers/staging/intel_sst/intel_sst_ipc.c
+++ b/drivers/staging/intel_sst/intel_sst_ipc.c
@@ -154,6 +154,37 @@ void sst_clear_interrupt(void)
sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
}
+void sst_restore_fw_context(void)
+{
+ struct snd_sst_ctxt_params fw_context;
+ struct ipc_post *msg = NULL;
+
+ pr_debug("restore_fw_context\n");
+ /*check cpu type*/
+ if (sst_drv_ctx->pci_id != SST_MFLD_PCI_ID)
+ return;
+ /*not supported for rest*/
+ if (!sst_drv_ctx->fw_cntx_size)
+ return;
+ /*nothing to restore*/
+ pr_debug("restoring context......\n");
+ /*send msg to fw*/
+ if (sst_create_large_msg(&msg))
+ return;
+
+ sst_fill_header(&msg->header, IPC_IA_SET_FW_CTXT, 1, 0);
+ msg->header.part.data = sizeof(fw_context) + sizeof(u32);
+ fw_context.address = virt_to_phys((void *)sst_drv_ctx->fw_cntx);
+ fw_context.size = sst_drv_ctx->fw_cntx_size;
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32),
+ &fw_context, sizeof(fw_context));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ return;
+}
/*
* process_fw_init - process the FW init msg
*
@@ -184,13 +215,13 @@ int process_fw_init(struct sst_ipc_msg_wq *msg)
sst_drv_ctx->sst_state = SST_FW_RUNNING;
sst_drv_ctx->lpe_stalled = 0;
mutex_unlock(&sst_drv_ctx->sst_lock);
- pr_debug("FW Version %x.%x\n",
- init->fw_version.major, init->fw_version.minor);
- pr_debug("Build No %x Type %x\n",
- init->fw_version.build, init->fw_version.type);
+ pr_debug("FW Version %02x.%02x.%02x\n", init->fw_version.major,
+ init->fw_version.minor, init->fw_version.build);
+ pr_debug("Build Type %x\n", init->fw_version.type);
pr_debug(" Build date %s Time %s\n",
init->build_info.date, init->build_info.time);
sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, retval, NULL);
+ sst_restore_fw_context();
return retval;
}
/**
@@ -385,6 +416,24 @@ void sst_process_reply(struct work_struct *work)
}
break;
}
+
+ case IPC_IA_TUNING_PARAMS: {
+ pr_debug("sst:IPC_TUNING_PARAMS resp: %x\n", msg->header.full);
+ pr_debug("data value %x\n", msg->header.part.data);
+ if (msg->header.part.large) {
+ pr_debug("alg set failed\n");
+ sst_drv_ctx->ppp_params_blk.ret_code =
+ -msg->header.part.data;
+ } else {
+ pr_debug("alg set success\n");
+ sst_drv_ctx->ppp_params_blk.ret_code = 0;
+ }
+ if (sst_drv_ctx->ppp_params_blk.on == true) {
+ sst_drv_ctx->ppp_params_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
+ }
+
case IPC_IA_GET_FW_INFO: {
struct snd_sst_fw_info *fw_info =
(struct snd_sst_fw_info *)msg->mailbox;
@@ -615,12 +664,18 @@ void sst_process_reply(struct work_struct *work)
break;
case IPC_IA_FREE_STREAM:
+ str_info = &sst_drv_ctx->streams[str_id];
if (!msg->header.part.data) {
pr_debug("Stream %d freed\n", str_id);
} else {
pr_err("Free for %d ret error %x\n",
str_id, msg->header.part.data);
}
+ if (str_info->ctrl_blk.on == true) {
+ str_info->ctrl_blk.on = false;
+ str_info->ctrl_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
break;
case IPC_IA_ALLOC_STREAM: {
/* map to stream, call play */
@@ -699,6 +754,17 @@ void sst_process_reply(struct work_struct *work)
case IPC_IA_START_STREAM:
pr_debug("reply for START STREAM %x\n", msg->header.full);
break;
+
+ case IPC_IA_GET_FW_CTXT:
+ pr_debug("reply for get fw ctxt %x\n", msg->header.full);
+ if (msg->header.part.data)
+ sst_drv_ctx->fw_cntx_size = 0;
+ else
+ sst_drv_ctx->fw_cntx_size = *sst_drv_ctx->fw_cntx;
+ pr_debug("fw copied data %x\n", sst_drv_ctx->fw_cntx_size);
+ sst_wake_up_alloc_block(
+ sst_drv_ctx, str_id, msg->header.part.data, NULL);
+ break;
default:
/* Illegal case */
pr_err("process reply:default = %x\n", msg->header.full);
diff --git a/drivers/staging/intel_sst/intel_sst_pvt.c b/drivers/staging/intel_sst/intel_sst_pvt.c
index 01f8c3b..e034bea 100644
--- a/drivers/staging/intel_sst/intel_sst_pvt.c
+++ b/drivers/staging/intel_sst/intel_sst_pvt.c
@@ -203,7 +203,7 @@ int sst_create_large_msg(struct ipc_post **arg)
kfree(msg);
pr_err("kzalloc mailbox_data failed");
return -ENOMEM;
- };
+ }
*arg = msg;
return 0;
}
diff --git a/drivers/staging/intel_sst/intel_sst_stream.c b/drivers/staging/intel_sst/intel_sst_stream.c
index dd58be5..be4565e 100644
--- a/drivers/staging/intel_sst/intel_sst_stream.c
+++ b/drivers/staging/intel_sst/intel_sst_stream.c
@@ -31,6 +31,7 @@
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/sched.h>
+#include <linux/delay.h>
#include "intel_sst_ioctl.h"
#include "intel_sst.h"
#include "intel_sst_fw_ipc.h"
@@ -47,7 +48,7 @@
*/
int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot)
{
- if (device > MAX_NUM_STREAMS_MFLD) {
+ if (device >= MAX_NUM_STREAMS_MFLD) {
pr_debug("device type invalid %d\n", device);
return -EINVAL;
}
@@ -72,6 +73,8 @@ int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot)
*pcm_slot = 0x07;
else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 4)
*pcm_slot = 0x0F;
+ else if (device == SND_SST_DEVICE_CAPTURE && num_chan > 4)
+ *pcm_slot = 0x1F;
else {
pr_debug("No condition satisfied.. ret err\n");
return -EINVAL;
@@ -519,10 +522,6 @@ int sst_drain_stream(int str_id)
str_info->data_blk.on = true;
retval = sst_wait_interruptible(sst_drv_ctx, &str_info->data_blk);
str_info->need_draining = false;
- if (retval == -SST_ERR_INVALID_STREAM_ID) {
- retval = -EINVAL;
- sst_clean_stream(str_info);
- }
return retval;
}
@@ -563,6 +562,12 @@ int sst_free_stream(int str_id)
str_info->data_blk.ret_code = 0;
wake_up(&sst_drv_ctx->wait_queue);
}
+ str_info->data_blk.on = true;
+ str_info->data_blk.condition = false;
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ pr_debug("wait for free returned %d\n", retval);
+ msleep(100);
mutex_lock(&sst_drv_ctx->stream_lock);
sst_clean_stream(str_info);
mutex_unlock(&sst_drv_ctx->stream_lock);
diff --git a/drivers/staging/intel_sst/intel_sst_stream_encoded.c b/drivers/staging/intel_sst/intel_sst_stream_encoded.c
index d5f07b8..2be58c5 100644
--- a/drivers/staging/intel_sst/intel_sst_stream_encoded.c
+++ b/drivers/staging/intel_sst/intel_sst_stream_encoded.c
@@ -363,7 +363,6 @@ int sst_parse_target(struct snd_sst_slot_info *slot)
pr_err("SST_Activate_target_fail\n");
else
pr_err("SST_Activate_target_pass\n");
- return retval;
} else if (slot->action == SND_SST_PORT_PREPARE &&
slot->device_type == SND_SST_DEVICE_PCM) {
retval = sst_prepare_target(slot);
@@ -371,12 +370,11 @@ int sst_parse_target(struct snd_sst_slot_info *slot)
pr_err("SST_prepare_target_fail\n");
else
pr_err("SST_prepare_target_pass\n");
- return retval;
} else {
pr_err("slot_action : %d, device_type: %d\n",
slot->action, slot->device_type);
- return retval;
}
+ return retval;
}
int sst_send_target(struct snd_sst_target_device *target)
@@ -886,8 +884,7 @@ static int sst_prepare_input_buffers_rar(struct stream_info *str_info,
int *input_index, int *in_copied,
int *input_index_valid_size, int *new_entry_flag)
{
- int retval = 0;
- int i;
+ int retval = 0, i;
if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) {
struct RAR_buffer rar_buffers;
@@ -924,7 +921,6 @@ static int sst_prepare_input_buffers_rar(struct stream_info *str_info,
return retval;
}
#endif
-
/*This function is used to prepare the kernel input buffers with contents
before sending for decode*/
static int sst_prepare_input_buffers(struct stream_info *str_info,
diff --git a/drivers/staging/intel_sst/intelmid.c b/drivers/staging/intel_sst/intelmid.c
index ebb6d03..25656ad 100644
--- a/drivers/staging/intel_sst/intelmid.c
+++ b/drivers/staging/intel_sst/intelmid.c
@@ -33,17 +33,20 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/firmware.h>
+#include <linux/input.h>
#include <sound/control.h>
#include <asm/mrst.h>
#include <sound/pcm.h>
-#include "jack.h"
+#include <sound/jack.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
+#include <linux/gpio.h>
#include "intel_sst.h"
#include "intel_sst_ioctl.h"
#include "intel_sst_fw_ipc.h"
#include "intel_sst_common.h"
#include "intelmid_snd_control.h"
+#include "intelmid_adc_control.h"
#include "intelmid.h"
MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
@@ -65,7 +68,14 @@ MODULE_PARM_DESC(card_id, "ID string for INTELMAD soundcard.");
int sst_card_vendor_id;
int intelmid_audio_interrupt_enable;/*checkpatch fix*/
-
+struct snd_intelmad *intelmad_drv;
+
+#define INFO(_cpu_id, _irq_cache, _size) \
+ ((kernel_ulong_t)&(struct snd_intelmad_probe_info) { \
+ .cpu_id = (_cpu_id), \
+ .irq_cache = (_irq_cache), \
+ .size = (_size), \
+ })
/* Data path functionalities */
static struct snd_pcm_hardware snd_intelmad_stream = {
.info = (SNDRV_PCM_INFO_INTERLEAVED |
@@ -187,7 +197,7 @@ static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream)
return ret_val;
}
- ret_val = snd_intelmad_alloc_stream(substream);
+ ret_val = snd_intelmad_alloc_stream(substream);
if (ret_val < 0)
return ret_val;
stream->dbg_cum_bytes = 0;
@@ -326,6 +336,16 @@ static int snd_intelmad_open(struct snd_pcm_substream *substream,
runtime = substream->runtime;
/* set the runtime hw parameter with local snd_pcm_hardware struct */
runtime->hw = snd_intelmad_stream;
+ if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) {
+ /*
+ * MRST firmware currently denies stereo recording requests.
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ runtime->hw.formats = (SNDRV_PCM_FMTBIT_S16 |
+ SNDRV_PCM_FMTBIT_U16);
+ runtime->hw.channels_max = 1;
+ }
+ }
if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) {
runtime->hw = snd_intelmad_stream;
runtime->hw.rates = SNDRV_PCM_RATE_48000;
@@ -426,7 +446,55 @@ static struct snd_pcm_ops snd_intelmad_capture_ops = {
.pointer = snd_intelmad_pcm_pointer,
};
+int intelmad_get_mic_bias(void)
+{
+ struct snd_pmic_ops *pmic_ops;
+
+ if (!intelmad_drv || !intelmad_drv->sstdrv_ops)
+ return -ENODEV;
+ pmic_ops = intelmad_drv->sstdrv_ops->scard_ops;
+ if (pmic_ops && pmic_ops->pmic_get_mic_bias)
+ return pmic_ops->pmic_get_mic_bias(intelmad_drv);
+ else
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(intelmad_get_mic_bias);
+
+int intelmad_set_headset_state(int state)
+{
+ struct snd_pmic_ops *pmic_ops;
+
+ if (!intelmad_drv || !intelmad_drv->sstdrv_ops)
+ return -ENODEV;
+ pmic_ops = intelmad_drv->sstdrv_ops->scard_ops;
+ if (pmic_ops && pmic_ops->pmic_set_headset_state)
+ return pmic_ops->pmic_set_headset_state(state);
+ else
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(intelmad_set_headset_state);
+
+void sst_process_mad_jack_detection(struct work_struct *work)
+{
+ u8 interrupt_status;
+ struct mad_jack_msg_wq *mad_jack_detect =
+ container_of(work, struct mad_jack_msg_wq, wq);
+
+ struct snd_intelmad *intelmaddata =
+ mad_jack_detect->intelmaddata;
+ if (!intelmaddata)
+ return;
+
+ interrupt_status = mad_jack_detect->intsts;
+ if (intelmaddata->sstdrv_ops && intelmaddata->sstdrv_ops->scard_ops
+ && intelmaddata->sstdrv_ops->scard_ops->pmic_irq_cb) {
+ intelmaddata->sstdrv_ops->scard_ops->pmic_irq_cb(
+ (void *)intelmaddata, interrupt_status);
+ intelmaddata->sstdrv_ops->scard_ops->pmic_jack_enable();
+ }
+ kfree(mad_jack_detect);
+}
/**
* snd_intelmad_intr_handler- interrupt handler
*
@@ -439,15 +507,17 @@ static irqreturn_t snd_intelmad_intr_handler(int irq, void *dev)
{
struct snd_intelmad *intelmaddata =
(struct snd_intelmad *)dev;
- u8 intsts;
-
- memcpy_fromio(&intsts,
+ u8 interrupt_status;
+ struct mad_jack_msg_wq *mad_jack_msg;
+ memcpy_fromio(&interrupt_status,
((void *)(intelmaddata->int_base)),
sizeof(u8));
- intelmaddata->mad_jack_msg.intsts = intsts;
- intelmaddata->mad_jack_msg.intelmaddata = intelmaddata;
- queue_work(intelmaddata->mad_jack_wq, &intelmaddata->mad_jack_msg.wq);
+ mad_jack_msg = kzalloc(sizeof(*mad_jack_msg), GFP_ATOMIC);
+ mad_jack_msg->intsts = interrupt_status;
+ mad_jack_msg->intelmaddata = intelmaddata;
+ INIT_WORK(&mad_jack_msg->wq, sst_process_mad_jack_detection);
+ queue_work(intelmaddata->mad_jack_wq, &mad_jack_msg->wq);
return IRQ_HANDLED;
}
@@ -460,286 +530,22 @@ void sst_mad_send_jack_report(struct snd_jack *jack,
pr_debug("MAD error jack empty\n");
} else {
- pr_debug("MAD send jack report for = %d!!!\n", status);
- pr_debug("MAD send jack report %d\n", jack->type);
snd_jack_report(jack, status);
-
- /*button pressed and released */
+ /* button pressed and released */
if (buttonpressevent)
snd_jack_report(jack, 0);
pr_debug("MAD sending jack report Done !!!\n");
}
-
-
-
-}
-
-void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
-{
- struct snd_jack *jack = NULL;
- unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
- struct sc_reg_access sc_access[] = {
- {0x187, 0x00, MASK7},
- {0x188, 0x10, MASK4},
- {0x18b, 0x10, MASK4},
- };
-
- struct sc_reg_access sc_access_write[] = {
- {0x198, 0x00, 0x0},
- };
-
- if (intsts & 0x4) {
-
- if (!(intelmid_audio_interrupt_enable)) {
- pr_debug("Audio interrupt enable\n");
- sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
-
- sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1);
- intelmid_audio_interrupt_enable = 1;
- intelmaddata->jack[0].jack_status = 0;
- intelmaddata->jack[1].jack_status = 0;
-
- }
- /* send headphone detect */
- pr_debug("MAD headphone %d\n", intsts & 0x4);
- jack = &intelmaddata->jack[0].jack;
- present = !(intelmaddata->jack[0].jack_status);
- intelmaddata->jack[0].jack_status = present;
- jack_event_flag = 1;
-
- }
-
- if (intsts & 0x2) {
- /* send short push */
- pr_debug("MAD short push %d\n", intsts & 0x2);
- jack = &intelmaddata->jack[2].jack;
- present = 1;
- jack_event_flag = 1;
- buttonpressflag = 1;
- }
- if (intsts & 0x1) {
- /* send long push */
- pr_debug("MAD long push %d\n", intsts & 0x1);
- jack = &intelmaddata->jack[3].jack;
- present = 1;
- jack_event_flag = 1;
- buttonpressflag = 1;
- }
- if (intsts & 0x8) {
- if (!(intelmid_audio_interrupt_enable)) {
- pr_debug("Audio interrupt enable\n");
- sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
-
- sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1);
- intelmid_audio_interrupt_enable = 1;
- intelmaddata->jack[0].jack_status = 0;
- intelmaddata->jack[1].jack_status = 0;
- }
- /* send headset detect */
- pr_debug("MAD headset = %d\n", intsts & 0x8);
- jack = &intelmaddata->jack[1].jack;
- present = !(intelmaddata->jack[1].jack_status);
- intelmaddata->jack[1].jack_status = present;
- jack_event_flag = 1;
- }
-
- if (jack_event_flag)
- sst_mad_send_jack_report(jack, buttonpressflag, present);
-}
-
-
-void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
-{
- u8 value = 0, jack_prev_state = 0;
- struct snd_jack *jack = NULL;
- unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
- time_t timediff;
- struct sc_reg_access sc_access_read = {0,};
- struct snd_pmic_ops *scard_ops;
-
- scard_ops = intelmaddata->sstdrv_ops->scard_ops;
-
- pr_debug("previous value: %x\n", intelmaddata->jack_prev_state);
-
- if (!(intelmid_audio_interrupt_enable)) {
- pr_debug("Audio interrupt enable\n");
- intelmaddata->jack_prev_state = 0xC0;
- intelmid_audio_interrupt_enable = 1;
- }
-
- if (intsts & 0x2) {
- jack_prev_state = intelmaddata->jack_prev_state;
- if (intelmaddata->pmic_status == PMIC_INIT) {
- sc_access_read.reg_addr = 0x201;
- sst_sc_reg_access(&sc_access_read, PMIC_READ, 1);
- value = (sc_access_read.value);
- pr_debug("value returned = 0x%x\n", value);
- }
-
- if (jack_prev_state == 0xc0 && value == 0x40) {
- /*headset detected. */
- pr_debug("MAD headset inserted\n");
- jack = &intelmaddata->jack[1].jack;
- present = 1;
- jack_event_flag = 1;
- intelmaddata->jack[1].jack_status = 1;
-
- }
-
- if (jack_prev_state == 0xc0 && value == 0x00) {
- /* headphone detected. */
- pr_debug("MAD headphone inserted\n");
- jack = &intelmaddata->jack[0].jack;
- present = 1;
- jack_event_flag = 1;
-
- }
-
- if (jack_prev_state == 0x40 && value == 0xc0) {
- /*headset removed*/
- pr_debug("Jack headset status %d\n",
- intelmaddata->jack[1].jack_status);
- pr_debug("MAD headset removed\n");
- jack = &intelmaddata->jack[1].jack;
- present = 0;
- jack_event_flag = 1;
- intelmaddata->jack[1].jack_status = 0;
- }
-
- if (jack_prev_state == 0x00 && value == 0xc0) {
- /* headphone detected. */
- pr_debug("Jack headphone status %d\n",
- intelmaddata->jack[0].jack_status);
- pr_debug("headphone removed\n");
- jack = &intelmaddata->jack[0].jack;
- present = 0;
- jack_event_flag = 1;
- }
-
- if (jack_prev_state == 0x40 && value == 0x00) {
- /*button pressed*/
- do_gettimeofday(&intelmaddata->jack[1].buttonpressed);
- pr_debug("MAD button press detected\n");
- }
-
-
- if (jack_prev_state == 0x00 && value == 0x40) {
- if (intelmaddata->jack[1].jack_status) {
- /*button pressed*/
- do_gettimeofday(
- &intelmaddata->jack[1].buttonreleased);
- /*button pressed */
- pr_debug("Button Released detected\n");
- timediff = intelmaddata->jack[1].
- buttonreleased.tv_sec - intelmaddata->
- jack[1].buttonpressed.tv_sec;
- buttonpressflag = 1;
- if (timediff > 1) {
- pr_debug("long press detected\n");
- /* send headphone detect/undetect */
- jack = &intelmaddata->jack[3].jack;
- present = 1;
- jack_event_flag = 1;
- } else {
- pr_debug("short press detected\n");
- /* send headphone detect/undetect */
- jack = &intelmaddata->jack[2].jack;
- present = 1;
- jack_event_flag = 1;
- }
- }
-
- }
- intelmaddata->jack_prev_state = value;
- }
- if (jack_event_flag)
- sst_mad_send_jack_report(jack, buttonpressflag, present);
-}
-
-
-void sst_mad_jackdetection_nec(u8 intsts, struct snd_intelmad *intelmaddata)
-{
- u8 value = 0;
- struct snd_jack *jack = NULL;
- unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
- struct sc_reg_access sc_access_read = {0,};
-
- if (intelmaddata->pmic_status == PMIC_INIT) {
- sc_access_read.reg_addr = 0x132;
- sst_sc_reg_access(&sc_access_read, PMIC_READ, 1);
- value = (sc_access_read.value);
- pr_debug("value returned = 0x%x\n", value);
- }
- if (intsts & 0x1) {
- pr_debug("headset detected\n");
- /* send headset detect/undetect */
- jack = &intelmaddata->jack[1].jack;
- present = (value == 0x1) ? 1 : 0;
- jack_event_flag = 1;
- }
- if (intsts & 0x2) {
- pr_debug("headphone detected\n");
- /* send headphone detect/undetect */
- jack = &intelmaddata->jack[0].jack;
- present = (value == 0x2) ? 1 : 0;
- jack_event_flag = 1;
- }
- if (intsts & 0x4) {
- pr_debug("short push detected\n");
- /* send short push */
- jack = &intelmaddata->jack[2].jack;
- present = 1;
- jack_event_flag = 1;
- buttonpressflag = 1;
- }
- if (intsts & 0x8) {
- pr_debug("long push detected\n");
- /* send long push */
- jack = &intelmaddata->jack[3].jack;
- present = 1;
- jack_event_flag = 1;
- buttonpressflag = 1;
- }
-
- if (jack_event_flag)
- sst_mad_send_jack_report(jack, buttonpressflag, present);
-
-
-}
-
-void sst_process_mad_jack_detection(struct work_struct *work)
-{
- u8 intsts;
- struct mad_jack_msg_wq *mad_jack_detect =
- container_of(work, struct mad_jack_msg_wq, wq);
-
- struct snd_intelmad *intelmaddata =
- mad_jack_detect->intelmaddata;
-
- intsts = mad_jack_detect->intsts;
-
- switch (intelmaddata->sstdrv_ops->vendor_id) {
- case SND_FS:
- sst_mad_jackdetection_fs(intsts , intelmaddata);
- break;
- case SND_MX:
- sst_mad_jackdetection_mx(intsts , intelmaddata);
- break;
- case SND_NC:
- sst_mad_jackdetection_nec(intsts , intelmaddata);
- break;
- }
}
-
static int __devinit snd_intelmad_register_irq(
- struct snd_intelmad *intelmaddata)
+ struct snd_intelmad *intelmaddata, unsigned int regbase,
+ unsigned int regsize)
{
int ret_val;
- u32 regbase = AUDINT_BASE, regsize = 8;
char *drv_name;
- pr_debug("irq reg done, regbase 0x%x, regsize 0x%x\n",
+ pr_debug("irq reg regbase 0x%x, regsize 0x%x\n",
regbase, regsize);
intelmaddata->int_base = ioremap_nocache(regbase, regsize);
if (!intelmaddata->int_base)
@@ -797,6 +603,7 @@ static int __devinit snd_intelmad_sst_register(
intelmaddata->sstdrv_ops->scard_ops->input_dev_id = DMIC;
intelmaddata->sstdrv_ops->scard_ops->output_dev_id =
STEREO_HEADPHONE;
+ intelmaddata->sstdrv_ops->scard_ops->lineout_dev_id = NONE;
}
/* registering with SST driver to get access to SST APIs to use */
@@ -805,13 +612,15 @@ static int __devinit snd_intelmad_sst_register(
pr_err("sst card registration failed\n");
return ret_val;
}
- sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
-
sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id;
intelmaddata->pmic_status = PMIC_UNINIT;
return ret_val;
}
+static void snd_intelmad_page_free(struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
/* Driver Init/exit functionalities */
/**
* snd_intelmad_pcm_new - to setup pcm for the card
@@ -863,6 +672,7 @@ static int __devinit snd_intelmad_pcm_new(struct snd_card *card,
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, cap_ops);
/* setup private data which can be retrieved when required */
pcm->private_data = intelmaddata;
+ pcm->private_free = snd_intelmad_page_free;
pcm->info_flags = 0;
strncpy(pcm->name, card->shortname, strlen(card->shortname));
/* allocate dma pages for ALSA stream operations */
@@ -907,8 +717,12 @@ static int snd_intelmad_jack(struct snd_intelmad *intelmaddata)
pr_debug("snd_intelmad_jack called\n");
jack = &intelmaddata->jack[0].jack;
- retval = snd_jack_new(intelmaddata->card, "Headphone",
- SND_JACK_HEADPHONE, &jack);
+ snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PHONE);
+ retval = snd_jack_new(intelmaddata->card, "Intel(R) MID Audio Jack",
+ SND_JACK_HEADPHONE | SND_JACK_HEADSET |
+ SW_JACK_PHYSICAL_INSERT | SND_JACK_BTN_0
+ | SND_JACK_BTN_1, &jack);
+ pr_debug("snd_intelmad_jack called\n");
if (retval < 0)
return retval;
snd_jack_report(jack, 0);
@@ -916,40 +730,6 @@ static int snd_intelmad_jack(struct snd_intelmad *intelmaddata)
jack->private_data = jack;
intelmaddata->jack[0].jack = *jack;
-
- jack = &intelmaddata->jack[1].jack;
- retval = snd_jack_new(intelmaddata->card, "Headset",
- SND_JACK_HEADSET, &jack);
- if (retval < 0)
- return retval;
-
-
-
- jack->private_data = jack;
- intelmaddata->jack[1].jack = *jack;
-
-
- jack = &intelmaddata->jack[2].jack;
- retval = snd_jack_new(intelmaddata->card, "Short Press",
- SND_JACK_HS_SHORT_PRESS, &jack);
- if (retval < 0)
- return retval;
-
-
- jack->private_data = jack;
- intelmaddata->jack[2].jack = *jack;
-
-
- jack = &intelmaddata->jack[3].jack;
- retval = snd_jack_new(intelmaddata->card, "Long Press",
- SND_JACK_HS_LONG_PRESS, &jack);
- if (retval < 0)
- return retval;
-
-
- jack->private_data = jack;
- intelmaddata->jack[3].jack = *jack;
-
return retval;
}
@@ -1002,14 +782,14 @@ static int snd_intelmad_dev_free(struct snd_device *device)
intelmaddata = device->device_data;
pr_debug("snd_intelmad_dev_free called\n");
- snd_card_free(intelmaddata->card);
- /*genl_unregister_family(&audio_event_genl_family);*/
unregister_sst_card(intelmaddata->sstdrv_ops);
/* free allocated memory for internal context */
destroy_workqueue(intelmaddata->mad_jack_wq);
+ device->device_data = NULL;
kfree(intelmaddata->sstdrv_ops);
kfree(intelmaddata);
+
return 0;
}
@@ -1040,9 +820,10 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
int ret_val;
struct snd_intelmad *intelmaddata;
const struct platform_device_id *id = platform_get_device_id(pdev);
- unsigned int cpu_id = (unsigned int)id->driver_data;
+ struct snd_intelmad_probe_info *info = (void *)id->driver_data;
- pr_debug("probe for %s cpu_id %d\n", pdev->name, cpu_id);
+ pr_debug("probe for %s cpu_id %d\n", pdev->name, info->cpu_id);
+ pr_debug("rq_chache %x of size %x\n", info->irq_cache, info->size);
if (!strcmp(pdev->name, DRIVER_NAME_MRST))
pr_debug("detected MRST\n");
else if (!strcmp(pdev->name, DRIVER_NAME_MFLD))
@@ -1051,7 +832,8 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
pr_err("detected unknown device abort!!\n");
return -EIO;
}
- if ((cpu_id < CPU_CHIP_LINCROFT) || (cpu_id > CPU_CHIP_PENWELL)) {
+ if ((info->cpu_id < CPU_CHIP_LINCROFT) ||
+ (info->cpu_id > CPU_CHIP_PENWELL)) {
pr_err("detected unknown cpu_id abort!!\n");
return -EIO;
}
@@ -1061,6 +843,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
pr_debug("mem alloctn fail\n");
return -ENOMEM;
}
+ intelmad_drv = intelmaddata;
/* allocate memory for LPE API set */
intelmaddata->sstdrv_ops = kzalloc(sizeof(struct intel_sst_card_ops),
@@ -1071,7 +854,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
return -ENOMEM;
}
- intelmaddata->cpu_id = cpu_id;
+ intelmaddata->cpu_id = info->cpu_id;
/* create a card instance with ALSA framework */
ret_val = snd_card_create(card_index, card_id, THIS_MODULE, 0, &card);
if (ret_val) {
@@ -1095,7 +878,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
ret_val = snd_intelmad_sst_register(intelmaddata);
if (ret_val) {
pr_err("snd_intelmad_sst_register failed\n");
- goto free_allocs;
+ goto set_null_data;
}
intelmaddata->pmic_status = PMIC_INIT;
@@ -1103,20 +886,21 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
ret_val = snd_intelmad_pcm(card, intelmaddata);
if (ret_val) {
pr_err("snd_intelmad_pcm failed\n");
- goto free_allocs;
+ goto free_sst;
}
ret_val = snd_intelmad_mixer(intelmaddata);
if (ret_val) {
pr_err("snd_intelmad_mixer failed\n");
- goto free_allocs;
+ goto free_card;
}
ret_val = snd_intelmad_jack(intelmaddata);
if (ret_val) {
pr_err("snd_intelmad_jack failed\n");
- goto free_allocs;
+ goto free_card;
}
+ intelmaddata->adc_address = mid_initialize_adc();
/*create work queue for jack interrupt*/
INIT_WORK(&intelmaddata->mad_jack_msg.wq,
@@ -1124,33 +908,48 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
intelmaddata->mad_jack_wq = create_workqueue("sst_mad_jack_wq");
if (!intelmaddata->mad_jack_wq)
- goto free_mad_jack_wq;
+ goto free_card;
- ret_val = snd_intelmad_register_irq(intelmaddata);
+ ret_val = snd_intelmad_register_irq(intelmaddata,
+ info->irq_cache, info->size);
if (ret_val) {
pr_err("snd_intelmad_register_irq fail\n");
- goto free_allocs;
+ goto free_mad_jack_wq;
}
/* internal function call to register device with ALSA */
ret_val = snd_intelmad_create(intelmaddata, card);
if (ret_val) {
pr_err("snd_intelmad_create failed\n");
- goto free_allocs;
+ goto set_pvt_data;
}
card->private_data = &intelmaddata;
snd_card_set_dev(card, &pdev->dev);
ret_val = snd_card_register(card);
if (ret_val) {
pr_err("snd_card_register failed\n");
- goto free_allocs;
+ goto set_pvt_data;
+ }
+ if (pdev->dev.platform_data) {
+ int gpio_amp = *(int *)pdev->dev.platform_data;
+ if (gpio_request_one(gpio_amp, GPIOF_OUT_INIT_LOW, "amp power"))
+ gpio_amp = 0;
+ intelmaddata->sstdrv_ops->scard_ops->gpio_amp = gpio_amp;
}
pr_debug("snd_intelmad_probe complete\n");
return ret_val;
+set_pvt_data:
+ card->private_data = NULL;
free_mad_jack_wq:
destroy_workqueue(intelmaddata->mad_jack_wq);
+free_card:
+ snd_card_free(intelmaddata->card);
+free_sst:
+ unregister_sst_card(intelmaddata->sstdrv_ops);
+set_null_data:
+ platform_set_drvdata(pdev, NULL);
free_allocs:
pr_err("probe failed\n");
snd_card_free(card);
@@ -1165,13 +964,13 @@ static int snd_intelmad_remove(struct platform_device *pdev)
struct snd_intelmad *intelmaddata = platform_get_drvdata(pdev);
if (intelmaddata) {
+ if (intelmaddata->sstdrv_ops->scard_ops->gpio_amp)
+ gpio_free(intelmaddata->sstdrv_ops->scard_ops->gpio_amp);
+ free_irq(intelmaddata->irq, intelmaddata);
snd_card_free(intelmaddata->card);
- unregister_sst_card(intelmaddata->sstdrv_ops);
- /* free allocated memory for internal context */
- destroy_workqueue(intelmaddata->mad_jack_wq);
- kfree(intelmaddata->sstdrv_ops);
- kfree(intelmaddata);
}
+ intelmad_drv = NULL;
+ platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -1179,8 +978,8 @@ static int snd_intelmad_remove(struct platform_device *pdev)
* Driver initialization and exit
*********************************************************************/
static const struct platform_device_id snd_intelmad_ids[] = {
- {DRIVER_NAME_MRST, CPU_CHIP_LINCROFT},
- {DRIVER_NAME_MFLD, CPU_CHIP_PENWELL},
+ {DRIVER_NAME_MRST, INFO(CPU_CHIP_LINCROFT, AUDINT_BASE, 1)},
+ {DRIVER_NAME_MFLD, INFO(CPU_CHIP_PENWELL, 0xFFFF7FCD, 1)},
{"", 0},
};
diff --git a/drivers/staging/intel_sst/intelmid.h b/drivers/staging/intel_sst/intelmid.h
index e77da87..14a7ba0 100644
--- a/drivers/staging/intel_sst/intelmid.h
+++ b/drivers/staging/intel_sst/intelmid.h
@@ -28,6 +28,7 @@
#define __INTELMID_H
#include <linux/time.h>
+#include <sound/jack.h>
#define DRIVER_NAME_MFLD "msic_audio"
#define DRIVER_NAME_MRST "pmic_audio"
@@ -43,7 +44,7 @@
#define MAX_BUFFER (800*1024) /* for PCM */
#define MIN_BUFFER (800*1024)
#define MAX_PERIODS (1024*2)
-#define MIN_PERIODS 1
+#define MIN_PERIODS 2
#define MAX_PERIOD_BYTES MAX_BUFFER
#define MIN_PERIOD_BYTES 32
/*#define MIN_PERIOD_BYTES 160*/
@@ -53,12 +54,12 @@
#define STEREO_CNTL 2
#define MIN_CHANNEL 1
#define MAX_CHANNEL_AMIC 2
-#define MAX_CHANNEL_DMIC 4
+#define MAX_CHANNEL_DMIC 5
#define FIFO_SIZE 0 /* fifo not being used */
#define INTEL_MAD "Intel MAD"
-#define MAX_CTRL_MRST 7
-#define MAX_CTRL_MFLD 2
-#define MAX_CTRL 7
+#define MAX_CTRL_MRST 8
+#define MAX_CTRL_MFLD 7
+#define MAX_CTRL 8
#define MAX_VENDORS 4
/* TODO +6 db */
#define MAX_VOL 64
@@ -66,12 +67,17 @@
#define MIN_VOL 0
#define PLAYBACK_COUNT 1
#define CAPTURE_COUNT 1
+#define ADC_ONE_LSB_MULTIPLIER 2346
+
+#define MID_JACK_HS_LONG_PRESS SND_JACK_BTN_0
+#define MID_JACK_HS_SHORT_PRESS SND_JACK_BTN_1
extern int sst_card_vendor_id;
struct mad_jack {
struct snd_jack jack;
int jack_status;
+ int jack_dev_state;
struct timeval buttonpressed;
struct timeval buttonreleased;
};
@@ -83,6 +89,12 @@ struct mad_jack_msg_wq {
};
+struct snd_intelmad_probe_info {
+ unsigned int cpu_id;
+ unsigned int irq_cache;
+ unsigned int size;
+};
+
/**
* struct snd_intelmad - intelmad driver structure
*
@@ -116,10 +128,12 @@ struct snd_intelmad {
void __iomem *int_base;
int output_sel;
int input_sel;
+ int lineout_sel;
int master_mute;
struct mad_jack jack[4];
int playback_cnt;
int capture_cnt;
+ u16 adc_address;
struct mad_jack_msg_wq mad_jack_msg;
struct workqueue_struct *mad_jack_wq;
u8 jack_prev_state;
@@ -131,6 +145,8 @@ struct snd_control_val {
int playback_vol_min;
int capture_vol_max;
int capture_vol_min;
+ int master_vol_max;
+ int master_vol_min;
};
struct mad_stream_pvt {
@@ -161,8 +177,18 @@ enum _widget_ctrl {
PLAYBACK_MUTE,
CAPTURE_VOL,
CAPTURE_MUTE,
+ MASTER_VOL,
MASTER_MUTE
};
+enum _widget_ctrl_mfld {
+ LINEOUT_SEL_MFLD = 3,
+};
+enum hw_chs {
+ HW_CH0 = 0,
+ HW_CH1,
+ HW_CH2,
+ HW_CH3
+};
void period_elapsed(void *mad_substream);
int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream);
@@ -177,5 +203,7 @@ extern struct snd_control_val intelmad_ctrl_val[];
extern struct snd_kcontrol_new snd_intelmad_controls_mrst[];
extern struct snd_kcontrol_new snd_intelmad_controls_mfld[];
extern struct snd_pmic_ops *intelmad_vendor_ops[];
+void sst_mad_send_jack_report(struct snd_jack *jack,
+ int buttonpressevent , int status);
#endif /* __INTELMID_H */
diff --git a/drivers/staging/intel_sst/intelmid_adc_control.h b/drivers/staging/intel_sst/intelmid_adc_control.h
new file mode 100644
index 0000000..65d5c39
--- /dev/null
+++ b/drivers/staging/intel_sst/intelmid_adc_control.h
@@ -0,0 +1,193 @@
+#ifndef __INTELMID_ADC_CONTROL_H__
+#define __INTELMID_ADC_CONTROL_H_
+/*
+ * intelmid_adc_control.h - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-10 Intel Corporation
+ * Authors: R Durgadadoss <r.durgadoss@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Common private ADC declarations for SST
+ */
+
+
+#define MSIC_ADC1CNTL1 0x1C0
+#define MSIC_ADC_ENBL 0x10
+#define MSIC_ADC_START 0x08
+
+#define MSIC_ADC1CNTL3 0x1C2
+#define MSIC_ADCTHERM_ENBL 0x04
+#define MSIC_ADCRRDATA_ENBL 0x05
+
+#define MSIC_STOPBIT_MASK 16
+#define MSIC_ADCTHERM_MASK 4
+
+#define ADC_CHANLS_MAX 15 /* Number of ADC channels */
+#define ADC_LOOP_MAX (ADC_CHANLS_MAX - 1)
+
+/* ADC channel code values */
+#define AUDIO_DETECT_CODE 0x06
+
+/* ADC base addresses */
+#define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */
+#define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */
+
+
+/**
+ * configure_adc - enables/disables the ADC for conversion
+ * @val: zero: disables the ADC non-zero:enables the ADC
+ *
+ * Enable/Disable the ADC depending on the argument
+ *
+ * Can sleep
+ */
+static inline int configure_adc(int val)
+{
+ int ret;
+ struct sc_reg_access sc_access = {0,};
+
+
+ sc_access.reg_addr = MSIC_ADC1CNTL1;
+ ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
+ if (ret)
+ return ret;
+
+ if (val)
+ /* Enable and start the ADC */
+ sc_access.value |= (MSIC_ADC_ENBL | MSIC_ADC_START);
+ else
+ /* Just stop the ADC */
+ sc_access.value &= (~MSIC_ADC_START);
+ sc_access.reg_addr = MSIC_ADC1CNTL1;
+ return sst_sc_reg_access(&sc_access, PMIC_WRITE, 1);
+}
+
+/**
+ * reset_stopbit - sets the stop bit to 0 on the given channel
+ * @addr: address of the channel
+ *
+ * Can sleep
+ */
+static inline int reset_stopbit(uint16_t addr)
+{
+ int ret;
+ struct sc_reg_access sc_access = {0,};
+ sc_access.reg_addr = addr;
+ ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
+ if (ret)
+ return ret;
+ /* Set the stop bit to zero */
+ sc_access.reg_addr = addr;
+ sc_access.value = (sc_access.value) & 0xEF;
+ return sst_sc_reg_access(&sc_access, PMIC_WRITE, 1);
+}
+
+/**
+ * find_free_channel - finds an empty channel for conversion
+ *
+ * If the ADC is not enabled then start using 0th channel
+ * itself. Otherwise find an empty channel by looking for a
+ * channel in which the stopbit is set to 1. returns the index
+ * of the first free channel if succeeds or an error code.
+ *
+ * Context: can sleep
+ *
+ */
+static inline int find_free_channel(void)
+{
+ int ret;
+ int i;
+
+ struct sc_reg_access sc_access = {0,};
+
+ /* check whether ADC is enabled */
+ sc_access.reg_addr = MSIC_ADC1CNTL1;
+ ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
+ if (ret)
+ return ret;
+
+ if ((sc_access.value & MSIC_ADC_ENBL) == 0)
+ return 0;
+
+ /* ADC is already enabled; Looking for an empty channel */
+ for (i = 0; i < ADC_CHANLS_MAX; i++) {
+
+ sc_access.reg_addr = ADC_CHNL_START_ADDR + i;
+ ret = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
+ if (ret)
+ return ret;
+
+ if (sc_access.value & MSIC_STOPBIT_MASK) {
+ ret = i;
+ break;
+ }
+ }
+ return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret;
+}
+
+/**
+ * mid_initialize_adc - initializing the ADC
+ * @dev: our device structure
+ *
+ * Initialize the ADC for reading thermistor values. Can sleep.
+ */
+static inline int mid_initialize_adc(void)
+{
+ int base_addr, chnl_addr;
+ int ret;
+ static int channel_index;
+ struct sc_reg_access sc_access = {0,};
+
+ /* Index of the first channel in which the stop bit is set */
+ channel_index = find_free_channel();
+ if (channel_index < 0) {
+ pr_err("No free ADC channels");
+ return channel_index;
+ }
+
+ base_addr = ADC_CHNL_START_ADDR + channel_index;
+
+ if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) {
+ /* Reset stop bit for channels other than 0 and 12 */
+ ret = reset_stopbit(base_addr);
+ if (ret)
+ return ret;
+
+ /* Index of the first free channel */
+ base_addr++;
+ channel_index++;
+ }
+
+ /* Since this is the last channel, set the stop bit
+ to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
+ sc_access.reg_addr = base_addr;
+ sc_access.value = AUDIO_DETECT_CODE | 0x10;
+ ret = sst_sc_reg_access(&sc_access, PMIC_WRITE, 1);
+ if (ret) {
+ pr_err("unable to enable ADC");
+ return ret;
+ }
+
+ chnl_addr = ADC_DATA_START_ADDR + 2 * channel_index;
+ pr_debug("mid_initialize : %x", chnl_addr);
+ configure_adc(1);
+ return chnl_addr;
+}
+#endif
+
diff --git a/drivers/staging/intel_sst/intelmid_ctrl.c b/drivers/staging/intel_sst/intelmid_ctrl.c
index 69af070..19ec474 100644
--- a/drivers/staging/intel_sst/intelmid_ctrl.c
+++ b/drivers/staging/intel_sst/intelmid_ctrl.c
@@ -29,17 +29,37 @@
#include <sound/core.h>
#include <sound/control.h>
-#include "jack.h"
#include "intel_sst.h"
#include "intel_sst_ioctl.h"
#include "intelmid_snd_control.h"
#include "intelmid.h"
+#define HW_CH_BASE 4
+
+
+#define HW_CH_0 "Hw1"
+#define HW_CH_1 "Hw2"
+#define HW_CH_2 "Hw3"
+#define HW_CH_3 "Hw4"
+
+static char *router_dmics[] = { "DMIC1",
+ "DMIC2",
+ "DMIC3",
+ "DMIC4",
+ "DMIC5",
+ "DMIC6"
+ };
+
static char *out_names_mrst[] = {"Headphones",
"Internal speakers"};
static char *in_names_mrst[] = {"AMIC",
"DMIC",
"HS_MIC"};
+static char *line_out_names_mfld[] = {"Headset",
+ "IHF ",
+ "Vibra1 ",
+ "Vibra2 ",
+ "NONE "};
static char *out_names_mfld[] = {"Headset ",
"EarPiece "};
static char *in_names_mfld[] = {"AMIC",
@@ -60,9 +80,11 @@ struct snd_control_val intelmad_ctrl_val[MAX_VENDORS] = {
},
{
.playback_vol_max = 0,
- .playback_vol_min = -126,
+ .playback_vol_min = -31,
.capture_vol_max = 0,
.capture_vol_min = -31,
+ .master_vol_max = 0,
+ .master_vol_min = -126,
},
};
@@ -139,6 +161,15 @@ static int snd_intelmad_playback_volume_info(struct snd_kcontrol *kcontrol,
return 0;
}
+static int snd_intelmad_master_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ snd_intelmad_volume_info(uinfo, STEREO_CNTL,
+ intelmad_ctrl_val[sst_card_vendor_id].master_vol_max,
+ intelmad_ctrl_val[sst_card_vendor_id].master_vol_min);
+ return 0;
+}
+
/**
* snd_intelmad_device_info_mrst - provides information about the devices available
*
@@ -179,13 +210,27 @@ static int snd_intelmad_device_info_mrst(struct snd_kcontrol *kcontrol,
static int snd_intelmad_device_info_mfld(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
+ struct snd_pmic_ops *scard_ops;
+ struct snd_intelmad *intelmaddata;
+
WARN_ON(!kcontrol);
WARN_ON(!uinfo);
+
+ intelmaddata = kcontrol->private_data;
+
+ WARN_ON(!intelmaddata->sstdrv_ops);
+
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
/* setup device select as drop down controls with different values */
if (kcontrol->id.numid == OUTPUT_SEL)
uinfo->value.enumerated.items = ARRAY_SIZE(out_names_mfld);
- else
+ else if (kcontrol->id.numid == INPUT_SEL)
uinfo->value.enumerated.items = ARRAY_SIZE(in_names_mfld);
+ else if (kcontrol->id.numid == LINEOUT_SEL_MFLD) {
+ uinfo->value.enumerated.items = ARRAY_SIZE(line_out_names_mfld);
+ scard_ops->line_out_names_cnt = uinfo->value.enumerated.items;
+ } else
+ return -EINVAL;
uinfo->count = MONO_CNTL;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -195,10 +240,16 @@ static int snd_intelmad_device_info_mfld(struct snd_kcontrol *kcontrol,
strncpy(uinfo->value.enumerated.name,
out_names_mfld[uinfo->value.enumerated.item],
sizeof(uinfo->value.enumerated.name)-1);
- else
+ else if (kcontrol->id.numid == INPUT_SEL)
strncpy(uinfo->value.enumerated.name,
in_names_mfld[uinfo->value.enumerated.item],
sizeof(uinfo->value.enumerated.name)-1);
+ else if (kcontrol->id.numid == LINEOUT_SEL_MFLD)
+ strncpy(uinfo->value.enumerated.name,
+ line_out_names_mfld[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name)-1);
+ else
+ return -EINVAL;
return 0;
}
@@ -241,6 +292,11 @@ static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol,
case CAPTURE_VOL:
cntl_list[0] = PMIC_SND_CAPTURE_VOL;
break;
+
+ case MASTER_VOL:
+ cntl_list[0] = PMIC_SND_RIGHT_MASTER_VOL;
+ cntl_list[1] = PMIC_SND_LEFT_MASTER_VOL;
+ break;
default:
return -EINVAL;
}
@@ -251,7 +307,8 @@ static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol,
if (ret_val)
return ret_val;
- if (kcontrol->id.numid == PLAYBACK_VOL) {
+ if (kcontrol->id.numid == PLAYBACK_VOL ||
+ kcontrol->id.numid == MASTER_VOL) {
ret_val = scard_ops->get_vol(cntl_list[1], &value);
uval->value.integer.value[1] = value;
}
@@ -359,6 +416,12 @@ static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol,
case CAPTURE_VOL:
cntl_list[0] = PMIC_SND_CAPTURE_VOL;
break;
+
+ case MASTER_VOL:
+ cntl_list[0] = PMIC_SND_LEFT_MASTER_VOL;
+ cntl_list[1] = PMIC_SND_RIGHT_MASTER_VOL;
+ break;
+
default:
return -EINVAL;
}
@@ -368,7 +431,8 @@ static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol,
if (ret_val)
return ret_val;
- if (kcontrol->id.numid == PLAYBACK_VOL)
+ if (kcontrol->id.numid == PLAYBACK_VOL ||
+ kcontrol->id.numid == MASTER_VOL)
ret_val = scard_ops->set_vol(cntl_list[1],
uval->value.integer.value[1]);
return ret_val;
@@ -464,14 +528,36 @@ static int snd_intelmad_device_get(struct snd_kcontrol *kcontrol,
WARN_ON(!kcontrol);
intelmaddata = kcontrol->private_data;
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
if (intelmaddata->cpu_id == CPU_CHIP_PENWELL) {
- scard_ops = intelmaddata->sstdrv_ops->scard_ops;
if (kcontrol->id.numid == OUTPUT_SEL)
uval->value.enumerated.item[0] =
scard_ops->output_dev_id;
else if (kcontrol->id.numid == INPUT_SEL)
uval->value.enumerated.item[0] =
scard_ops->input_dev_id;
+ else if (kcontrol->id.numid == LINEOUT_SEL_MFLD)
+ uval->value.enumerated.item[0] =
+ scard_ops->lineout_dev_id;
+ else
+ return -EINVAL;
+ } else if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT) {
+ if (kcontrol->id.numid == OUTPUT_SEL)
+ /* There is a mismatch here.
+ * ALSA expects 1 for internal speaker.
+ * But internally, we may give 2 for internal speaker.
+ */
+ if (scard_ops->output_dev_id == MONO_EARPIECE ||
+ scard_ops->output_dev_id == INTERNAL_SPKR)
+ uval->value.enumerated.item[0] = MONO_EARPIECE;
+ else if (scard_ops->output_dev_id == STEREO_HEADPHONE)
+ uval->value.enumerated.item[0] =
+ STEREO_HEADPHONE;
+ else
+ return -EINVAL;
+ else if (kcontrol->id.numid == INPUT_SEL)
+ uval->value.enumerated.item[0] =
+ scard_ops->input_dev_id;
else
return -EINVAL;
} else
@@ -534,6 +620,11 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol,
uval->value.enumerated.item[0]);
intelmaddata->input_sel = uval->value.enumerated.item[0];
break;
+ case LINEOUT_SEL_MFLD:
+ ret_val = scard_ops->set_lineout_dev(
+ uval->value.enumerated.item[0]);
+ intelmaddata->lineout_sel = uval->value.enumerated.item[0];
+ break;
default:
return -EINVAL;
}
@@ -541,6 +632,151 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol,
return ret_val;
}
+static int snd_intelmad_device_dmic_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uval)
+{
+ struct snd_intelmad *intelmaddata;
+ struct snd_pmic_ops *scard_ops;
+
+ WARN_ON(!uval);
+ WARN_ON(!kcontrol);
+
+ intelmaddata = kcontrol->private_data;
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+
+ if (scard_ops->input_dev_id != DMIC) {
+ pr_debug("input dev = 0x%x\n", scard_ops->input_dev_id);
+ return 0;
+ }
+
+ if (intelmaddata->cpu_id == CPU_CHIP_PENWELL)
+ uval->value.enumerated.item[0] = kcontrol->private_value;
+ else
+ pr_debug(" CPU id = 0x%xis invalid.\n",
+ intelmaddata->cpu_id);
+ return 0;
+}
+
+void msic_set_bit(u8 index, unsigned int *available_dmics)
+{
+ *available_dmics |= (1 << index);
+}
+
+void msic_clear_bit(u8 index, unsigned int *available_dmics)
+{
+ *available_dmics &= ~(1 << index);
+}
+
+int msic_is_set_bit(u8 index, unsigned int *available_dmics)
+{
+ int ret_val;
+
+ ret_val = (*available_dmics & (1 << index));
+ return ret_val;
+}
+
+static int snd_intelmad_device_dmic_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uval)
+{
+ struct snd_intelmad *intelmaddata;
+ struct snd_pmic_ops *scard_ops;
+ int i, dmic_index;
+ unsigned int available_dmics;
+ int jump_count;
+ int max_dmics = ARRAY_SIZE(router_dmics);
+
+ WARN_ON(!uval);
+ WARN_ON(!kcontrol);
+
+ intelmaddata = kcontrol->private_data;
+ WARN_ON(!intelmaddata->sstdrv_ops);
+
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+ WARN_ON(!scard_ops);
+
+ if (scard_ops->input_dev_id != DMIC) {
+ pr_debug("input dev = 0x%x\n", scard_ops->input_dev_id);
+ return 0;
+ }
+
+ available_dmics = scard_ops->available_dmics;
+
+ if (kcontrol->private_value > uval->value.enumerated.item[0]) {
+ pr_debug("jump count -1.\n");
+ jump_count = -1;
+ } else {
+ pr_debug("jump count 1.\n");
+ jump_count = 1;
+ }
+
+ dmic_index = uval->value.enumerated.item[0];
+ pr_debug("set function. dmic_index = %d, avl_dmic = 0x%x\n",
+ dmic_index, available_dmics);
+ for (i = 0; i < max_dmics; i++) {
+ pr_debug("set function. loop index = 0x%x. dmic_index = 0x%x\n",
+ i, dmic_index);
+ if (!msic_is_set_bit(dmic_index, &available_dmics)) {
+ msic_clear_bit(kcontrol->private_value,
+ &available_dmics);
+ msic_set_bit(dmic_index, &available_dmics);
+ kcontrol->private_value = dmic_index;
+ scard_ops->available_dmics = available_dmics;
+ scard_ops->hw_dmic_map[kcontrol->id.numid-HW_CH_BASE] =
+ kcontrol->private_value;
+ scard_ops->set_hw_dmic_route
+ (kcontrol->id.numid-HW_CH_BASE);
+ return 0;
+ }
+
+ dmic_index += jump_count;
+
+ if (dmic_index > (max_dmics - 1) && jump_count == 1) {
+ pr_debug("Resettingthe dmic index to 0.\n");
+ dmic_index = 0;
+ } else if (dmic_index == -1 && jump_count == -1) {
+ pr_debug("Resetting the dmic index to 5.\n");
+ dmic_index = max_dmics - 1;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int snd_intelmad_device_dmic_info_mfld(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_intelmad *intelmaddata;
+ struct snd_pmic_ops *scard_ops;
+
+ uinfo->count = MONO_CNTL;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->value.enumerated.items = ARRAY_SIZE(router_dmics);
+
+ intelmaddata = kcontrol->private_data;
+ WARN_ON(!intelmaddata->sstdrv_ops);
+
+ scard_ops = intelmaddata->sstdrv_ops->scard_ops;
+ WARN_ON(!scard_ops);
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+
+ strncpy(uinfo->value.enumerated.name,
+ router_dmics[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name)-1);
+
+
+ msic_set_bit(kcontrol->private_value, &scard_ops->available_dmics);
+ pr_debug("info function. avl_dmic = 0x%x",
+ scard_ops->available_dmics);
+
+ scard_ops->hw_dmic_map[kcontrol->id.numid-HW_CH_BASE] =
+ kcontrol->private_value;
+
+ return 0;
+}
+
struct snd_kcontrol_new snd_intelmad_controls_mrst[MAX_CTRL] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -598,6 +834,15 @@ struct snd_kcontrol_new snd_intelmad_controls_mrst[MAX_CTRL] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_master_volume_info,
+ .get = snd_intelmad_volume_get,
+ .put = snd_intelmad_volume_set,
+ .private_value = 0,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = snd_intelmad_mute_info,
@@ -627,5 +872,50 @@ snd_intelmad_controls_mfld[MAX_CTRL_MFLD] __devinitdata = {
.put = snd_intelmad_device_set,
.private_value = 0,
},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Line out",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_device_info_mfld,
+ .get = snd_intelmad_device_get,
+ .put = snd_intelmad_device_set,
+ .private_value = 0,
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = HW_CH_0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_device_dmic_info_mfld,
+ .get = snd_intelmad_device_dmic_get,
+ .put = snd_intelmad_device_dmic_set,
+ .private_value = 0
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = HW_CH_1,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_device_dmic_info_mfld,
+ .get = snd_intelmad_device_dmic_get,
+ .put = snd_intelmad_device_dmic_set,
+ .private_value = 1
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = HW_CH_2,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_device_dmic_info_mfld,
+ .get = snd_intelmad_device_dmic_get,
+ .put = snd_intelmad_device_dmic_set,
+ .private_value = 2
+},
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = HW_CH_3,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_intelmad_device_dmic_info_mfld,
+ .get = snd_intelmad_device_dmic_get,
+ .put = snd_intelmad_device_dmic_set,
+ .private_value = 3
+}
};
diff --git a/drivers/staging/intel_sst/intelmid_msic_control.c b/drivers/staging/intel_sst/intelmid_msic_control.c
index da093ed..70cdb16 100644
--- a/drivers/staging/intel_sst/intelmid_msic_control.c
+++ b/drivers/staging/intel_sst/intelmid_msic_control.c
@@ -28,9 +28,15 @@
#include <linux/pci.h>
#include <linux/file.h>
+#include <linux/delay.h>
+#include <sound/control.h>
#include "intel_sst.h"
-#include "intel_sst_ioctl.h"
+#include <linux/input.h>
#include "intelmid_snd_control.h"
+#include "intelmid.h"
+
+#define AUDIOMUX12 0x24c
+#define AUDIOMUX34 0x24d
static int msic_init_card(void)
{
@@ -54,116 +60,359 @@ static int msic_init_card(void)
/*TI vibra w/a settings*/
{0x384, 0x80, 0},
{0x385, 0x80, 0},
- /*vibra settings*/
{0x267, 0x00, 0},
- {0x26A, 0x10, 0},
{0x261, 0x00, 0},
- {0x264, 0x10, 0},
/* pcm port setting */
{0x278, 0x00, 0},
{0x27B, 0x01, 0},
{0x27C, 0x0a, 0},
/* Set vol HSLRVOLCTRL, IHFVOL */
- {0x259, 0x04, 0},
- {0x25A, 0x04, 0},
- {0x25B, 0x04, 0},
- {0x25C, 0x04, 0},
+ {0x259, 0x08, 0},
+ {0x25A, 0x08, 0},
+ {0x25B, 0x08, 0},
+ {0x25C, 0x08, 0},
/* HSEPRXCTRL Enable the headset left and right FIR filters */
{0x250, 0x30, 0},
/* HSMIXER */
{0x256, 0x11, 0},
/* amic configuration */
- {0x249, 0x09, 0x0},
- {0x24A, 0x09, 0x0},
+ {0x249, 0x01, 0x0},
+ {0x24A, 0x01, 0x0},
/* unmask ocaudio/accdet interrupts */
{0x1d, 0x00, 0x00},
{0x1e, 0x00, 0x00},
};
snd_msic_ops.card_status = SND_CARD_INIT_DONE;
- sst_sc_reg_access(sc_access, PMIC_WRITE, 30);
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 28);
snd_msic_ops.pb_on = 0;
+ snd_msic_ops.pbhs_on = 0;
snd_msic_ops.cap_on = 0;
snd_msic_ops.input_dev_id = DMIC; /*def dev*/
snd_msic_ops.output_dev_id = STEREO_HEADPHONE;
+ snd_msic_ops.jack_interrupt_status = false;
pr_debug("msic init complete!!\n");
return 0;
}
+static int msic_line_out_restore(u8 value)
+{
+ struct sc_reg_access hs_drv_en[] = {
+ {0x25d, 0x03, 0x03},
+ };
+ struct sc_reg_access ep_drv_en[] = {
+ {0x25d, 0x40, 0x40},
+ };
+ struct sc_reg_access ihf_drv_en[] = {
+ {0x25d, 0x0c, 0x0c},
+ };
+ struct sc_reg_access vib1_drv_en[] = {
+ {0x25d, 0x10, 0x10},
+ };
+ struct sc_reg_access vib2_drv_en[] = {
+ {0x25d, 0x20, 0x20},
+ };
+ struct sc_reg_access pmode_enable[] = {
+ {0x381, 0x10, 0x10},
+ };
+ int retval = 0;
+
+ pr_debug("msic_lineout_restore_lineout_dev:%d\n", value);
+
+ switch (value) {
+ case HEADSET:
+ pr_debug("Selecting Lineout-HEADSET-restore\n");
+ if (snd_msic_ops.output_dev_id == STEREO_HEADPHONE)
+ retval = sst_sc_reg_access(hs_drv_en,
+ PMIC_READ_MODIFY, 1);
+ else
+ retval = sst_sc_reg_access(ep_drv_en,
+ PMIC_READ_MODIFY, 1);
+ break;
+ case IHF:
+ pr_debug("Selecting Lineout-IHF-restore\n");
+ retval = sst_sc_reg_access(ihf_drv_en, PMIC_READ_MODIFY, 1);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_enable, PMIC_READ_MODIFY, 1);
+ break;
+ case VIBRA1:
+ pr_debug("Selecting Lineout-Vibra1-restore\n");
+ retval = sst_sc_reg_access(vib1_drv_en, PMIC_READ_MODIFY, 1);
+ break;
+ case VIBRA2:
+ pr_debug("Selecting Lineout-VIBRA2-restore\n");
+ retval = sst_sc_reg_access(vib2_drv_en, PMIC_READ_MODIFY, 1);
+ break;
+ case NONE:
+ pr_debug("Selecting Lineout-NONE-restore\n");
+ break;
+ default:
+ return -EINVAL;
+ }
+ return retval;
+}
+static int msic_get_lineout_prvstate(void)
+{
+ struct sc_reg_access hs_ihf_drv[2] = {
+ {0x257, 0x0, 0x0},
+ {0x25d, 0x0, 0x0},
+ };
+ struct sc_reg_access vib1drv[2] = {
+ {0x264, 0x0, 0x0},
+ {0x25D, 0x0, 0x0},
+ };
+ struct sc_reg_access vib2drv[2] = {
+ {0x26A, 0x0, 0x0},
+ {0x25D, 0x0, 0x0},
+ };
+ int retval = 0, drv_en, dac_en, dev_id, mask;
+ for (dev_id = 0; dev_id < snd_msic_ops.line_out_names_cnt; dev_id++) {
+ switch (dev_id) {
+ case HEADSET:
+ pr_debug("msic_get_lineout_prvs_state: HEADSET\n");
+ sst_sc_reg_access(hs_ihf_drv, PMIC_READ, 2);
+
+ mask = (MASK0|MASK1);
+ dac_en = (hs_ihf_drv[0].value) & mask;
+
+ mask = ((MASK0|MASK1)|MASK6);
+ drv_en = (hs_ihf_drv[1].value) & mask;
+
+ if (dac_en && (!drv_en)) {
+ snd_msic_ops.prev_lineout_dev_id = HEADSET;
+ return retval;
+ }
+ break;
+ case IHF:
+ pr_debug("msic_get_lineout_prvstate: IHF\n");
+ sst_sc_reg_access(hs_ihf_drv, PMIC_READ, 2);
+
+ mask = (MASK2 | MASK3);
+ dac_en = (hs_ihf_drv[0].value) & mask;
+
+ mask = (MASK2 | MASK3);
+ drv_en = (hs_ihf_drv[1].value) & mask;
+
+ if (dac_en && (!drv_en)) {
+ snd_msic_ops.prev_lineout_dev_id = IHF;
+ return retval;
+ }
+ break;
+ case VIBRA1:
+ pr_debug("msic_get_lineout_prvstate: vibra1\n");
+ sst_sc_reg_access(vib1drv, PMIC_READ, 2);
+
+ mask = MASK1;
+ dac_en = (vib1drv[0].value) & mask;
+
+ mask = MASK4;
+ drv_en = (vib1drv[1].value) & mask;
+
+ if (dac_en && (!drv_en)) {
+ snd_msic_ops.prev_lineout_dev_id = VIBRA1;
+ return retval;
+ }
+ break;
+ case VIBRA2:
+ pr_debug("msic_get_lineout_prvstate: vibra2\n");
+ sst_sc_reg_access(vib2drv, PMIC_READ, 2);
+
+ mask = MASK1;
+ dac_en = (vib2drv[0].value) & mask;
+
+ mask = MASK5;
+ drv_en = ((vib2drv[1].value) & mask);
+
+ if (dac_en && (!drv_en)) {
+ snd_msic_ops.prev_lineout_dev_id = VIBRA2;
+ return retval;
+ }
+ break;
+ case NONE:
+ pr_debug("msic_get_lineout_prvstate: NONE\n");
+ snd_msic_ops.prev_lineout_dev_id = NONE;
+ return retval;
+ default:
+ pr_debug("Invalid device id\n");
+ snd_msic_ops.prev_lineout_dev_id = NONE;
+ return -EINVAL;
+ }
+ }
+ return retval;
+}
+static int msic_set_selected_lineout_dev(u8 value)
+{
+ struct sc_reg_access lout_hs[] = {
+ {0x25e, 0x33, 0xFF},
+ {0x25d, 0x0, 0x43},
+ };
+ struct sc_reg_access lout_ihf[] = {
+ {0x25e, 0x55, 0xff},
+ {0x25d, 0x0, 0x0c},
+ };
+ struct sc_reg_access lout_vibra1[] = {
+
+ {0x25e, 0x61, 0xff},
+ {0x25d, 0x0, 0x10},
+ };
+ struct sc_reg_access lout_vibra2[] = {
+
+ {0x25e, 0x16, 0xff},
+ {0x25d, 0x0, 0x20},
+ };
+ struct sc_reg_access lout_def[] = {
+ {0x25e, 0x66, 0x0},
+ };
+ struct sc_reg_access pmode_disable[] = {
+ {0x381, 0x00, 0x10},
+ };
+ struct sc_reg_access pmode_enable[] = {
+ {0x381, 0x10, 0x10},
+ };
+ int retval = 0;
+
+ pr_debug("msic_set_selected_lineout_dev:%d\n", value);
+ msic_get_lineout_prvstate();
+ msic_line_out_restore(snd_msic_ops.prev_lineout_dev_id);
+ snd_msic_ops.lineout_dev_id = value;
+
+ switch (value) {
+ case HEADSET:
+ pr_debug("Selecting Lineout-HEADSET\n");
+ if (snd_msic_ops.pb_on)
+ retval = sst_sc_reg_access(lout_hs,
+ PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_disable,
+ PMIC_READ_MODIFY, 1);
+ break;
+ case IHF:
+ pr_debug("Selecting Lineout-IHF\n");
+ if (snd_msic_ops.pb_on)
+ retval = sst_sc_reg_access(lout_ihf,
+ PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_enable,
+ PMIC_READ_MODIFY, 1);
+ break;
+ case VIBRA1:
+ pr_debug("Selecting Lineout-Vibra1\n");
+ if (snd_msic_ops.pb_on)
+ retval = sst_sc_reg_access(lout_vibra1,
+ PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_disable,
+ PMIC_READ_MODIFY, 1);
+ break;
+ case VIBRA2:
+ pr_debug("Selecting Lineout-VIBRA2\n");
+ if (snd_msic_ops.pb_on)
+ retval = sst_sc_reg_access(lout_vibra2,
+ PMIC_READ_MODIFY, 2);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_disable,
+ PMIC_READ_MODIFY, 1);
+ break;
+ case NONE:
+ pr_debug("Selecting Lineout-NONE\n");
+ retval = sst_sc_reg_access(lout_def,
+ PMIC_WRITE, 1);
+ if (retval)
+ return retval;
+ retval = sst_sc_reg_access(pmode_disable,
+ PMIC_READ_MODIFY, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return retval;
+}
+
static int msic_power_up_pb(unsigned int device)
{
- struct sc_reg_access sc_access1[] = {
+ struct sc_reg_access vaud[] = {
/* turn on the audio power supplies */
- {0x0DB, 0x05, 0},
+ {0x0DB, 0x07, 0},
+ };
+ struct sc_reg_access pll[] = {
+ /* turn on PLL */
+ {0x240, 0x20, 0},
+ };
+ struct sc_reg_access vhs[] = {
/* VHSP */
- {0x0DC, 0xFF, 0},
+ {0x0DC, 0x3D, 0},
/* VHSN */
{0x0DD, 0x3F, 0},
- /* turn on PLL */
- {0x240, 0x21, 0},
};
- struct sc_reg_access sc_access2[] = {
+ struct sc_reg_access hsdac[] = {
+ {0x382, 0x40, 0x40},
/* disable driver */
{0x25D, 0x0, 0x43},
/* DAC CONFIG ; both HP, LP on */
{0x257, 0x03, 0x03},
};
- struct sc_reg_access sc_access3[] = {
+ struct sc_reg_access hs_filter[] = {
/* HSEPRXCTRL Enable the headset left and right FIR filters */
{0x250, 0x30, 0},
/* HSMIXER */
{0x256, 0x11, 0},
};
- struct sc_reg_access sc_access4[] = {
+ struct sc_reg_access hs_enable[] = {
/* enable driver */
{0x25D, 0x3, 0x3},
+ {0x26C, 0x0, 0x2},
/* unmute the headset */
{ 0x259, 0x80, 0x80},
{ 0x25A, 0x80, 0x80},
};
- struct sc_reg_access sc_access_vihf[] = {
+ struct sc_reg_access vihf[] = {
/* VIHF ON */
- {0x0C9, 0x2D, 0x00},
+ {0x0C9, 0x27, 0x00},
};
- struct sc_reg_access sc_access22[] = {
+ struct sc_reg_access ihf_filter[] = {
/* disable driver */
{0x25D, 0x00, 0x0C},
/*Filer DAC enable*/
{0x251, 0x03, 0x03},
{0x257, 0x0C, 0x0C},
};
- struct sc_reg_access sc_access32[] = {
+ struct sc_reg_access ihf_en[] = {
/*enable drv*/
{0x25D, 0x0C, 0x0c},
};
- struct sc_reg_access sc_access42[] = {
+ struct sc_reg_access ihf_unmute[] = {
/*unmute headset*/
{0x25B, 0x80, 0x80},
{0x25C, 0x80, 0x80},
};
- struct sc_reg_access sc_access23[] = {
+ struct sc_reg_access epdac[] = {
/* disable driver */
{0x25D, 0x0, 0x43},
/* DAC CONFIG ; both HP, LP on */
{0x257, 0x03, 0x03},
};
- struct sc_reg_access sc_access43[] = {
+ struct sc_reg_access ep_enable[] = {
/* enable driver */
{0x25D, 0x40, 0x40},
/* unmute the headset */
{ 0x259, 0x80, 0x80},
{ 0x25A, 0x80, 0x80},
};
- struct sc_reg_access sc_access_vib[] = {
+ struct sc_reg_access vib1_en[] = {
/* enable driver, ADC */
{0x25D, 0x10, 0x10},
- {0x264, 0x02, 0x02},
+ {0x264, 0x02, 0x82},
};
- struct sc_reg_access sc_access_hap[] = {
+ struct sc_reg_access vib2_en[] = {
/* enable driver, ADC */
{0x25D, 0x20, 0x20},
- {0x26A, 0x02, 0x02},
+ {0x26A, 0x02, 0x82},
};
- struct sc_reg_access sc_access_pcm2[] = {
+ struct sc_reg_access pcm2_en[] = {
/* enable pcm 2 */
{0x27C, 0x1, 0x1},
};
@@ -176,89 +425,95 @@ static int msic_power_up_pb(unsigned int device)
}
pr_debug("powering up pb.... Device %d\n", device);
- sst_sc_reg_access(sc_access1, PMIC_WRITE, 4);
+ sst_sc_reg_access(vaud, PMIC_WRITE, 1);
+ msleep(1);
+ sst_sc_reg_access(pll, PMIC_WRITE, 1);
+ msleep(1);
switch (device) {
case SND_SST_DEVICE_HEADSET:
+ snd_msic_ops.pb_on = 1;
+ snd_msic_ops.pbhs_on = 1;
if (snd_msic_ops.output_dev_id == STEREO_HEADPHONE) {
- sst_sc_reg_access(sc_access2, PMIC_READ_MODIFY, 2);
- sst_sc_reg_access(sc_access3, PMIC_WRITE, 2);
- sst_sc_reg_access(sc_access4, PMIC_READ_MODIFY, 3);
+ sst_sc_reg_access(vhs, PMIC_WRITE, 2);
+ sst_sc_reg_access(hsdac, PMIC_READ_MODIFY, 3);
+ sst_sc_reg_access(hs_filter, PMIC_WRITE, 2);
+ sst_sc_reg_access(hs_enable, PMIC_READ_MODIFY, 4);
} else {
- sst_sc_reg_access(sc_access23, PMIC_READ_MODIFY, 2);
- sst_sc_reg_access(sc_access3, PMIC_WRITE, 2);
- sst_sc_reg_access(sc_access43, PMIC_READ_MODIFY, 3);
+ sst_sc_reg_access(epdac, PMIC_READ_MODIFY, 2);
+ sst_sc_reg_access(hs_filter, PMIC_WRITE, 2);
+ sst_sc_reg_access(ep_enable, PMIC_READ_MODIFY, 3);
}
- snd_msic_ops.pb_on = 1;
+ if (snd_msic_ops.lineout_dev_id == HEADSET)
+ msic_set_selected_lineout_dev(HEADSET);
break;
-
case SND_SST_DEVICE_IHF:
- sst_sc_reg_access(sc_access_vihf, PMIC_WRITE, 1);
- sst_sc_reg_access(sc_access22, PMIC_READ_MODIFY, 3);
- sst_sc_reg_access(sc_access32, PMIC_READ_MODIFY, 1);
- sst_sc_reg_access(sc_access42, PMIC_READ_MODIFY, 2);
+ snd_msic_ops.pb_on = 1;
+ sst_sc_reg_access(vihf, PMIC_WRITE, 1);
+ sst_sc_reg_access(ihf_filter, PMIC_READ_MODIFY, 3);
+ sst_sc_reg_access(ihf_en, PMIC_READ_MODIFY, 1);
+ sst_sc_reg_access(ihf_unmute, PMIC_READ_MODIFY, 2);
+ if (snd_msic_ops.lineout_dev_id == IHF)
+ msic_set_selected_lineout_dev(IHF);
break;
case SND_SST_DEVICE_VIBRA:
- sst_sc_reg_access(sc_access_vib, PMIC_READ_MODIFY, 2);
+ snd_msic_ops.pb_on = 1;
+ sst_sc_reg_access(vib1_en, PMIC_READ_MODIFY, 2);
+ if (snd_msic_ops.lineout_dev_id == VIBRA1)
+ msic_set_selected_lineout_dev(VIBRA1);
break;
case SND_SST_DEVICE_HAPTIC:
- sst_sc_reg_access(sc_access_hap, PMIC_READ_MODIFY, 2);
+ snd_msic_ops.pb_on = 1;
+ sst_sc_reg_access(vib2_en, PMIC_READ_MODIFY, 2);
+ if (snd_msic_ops.lineout_dev_id == VIBRA2)
+ msic_set_selected_lineout_dev(VIBRA2);
break;
default:
pr_warn("Wrong Device %d, selected %d\n",
device, snd_msic_ops.output_dev_id);
}
- return sst_sc_reg_access(sc_access_pcm2, PMIC_READ_MODIFY, 1);
+ return sst_sc_reg_access(pcm2_en, PMIC_READ_MODIFY, 1);
}
static int msic_power_up_cp(unsigned int device)
{
- struct sc_reg_access sc_access[] = {
+ struct sc_reg_access vaud[] = {
/* turn on the audio power supplies */
- {0x0DB, 0x05, 0},
- /* VHSP */
- {0x0DC, 0xFF, 0},
- /* VHSN */
- {0x0DD, 0x3F, 0},
+ {0x0DB, 0x07, 0},
+ };
+ struct sc_reg_access pll[] = {
/* turn on PLL */
- {0x240, 0x21, 0},
-
- /* Turn on DMIC supply */
- {0x247, 0xA0, 0x0},
- {0x240, 0x21, 0x0},
- {0x24C, 0x10, 0x0},
-
+ {0x240, 0x20, 0},
+ };
+ struct sc_reg_access dmic_bias[] = {
+ /* Turn on AMIC supply */
+ {0x247, 0xA0, 0xA0},
+ };
+ struct sc_reg_access dmic[] = {
/* mic demux enable */
- {0x245, 0x3F, 0x0},
- {0x246, 0x7, 0x0},
+ {0x245, 0x3F, 0x3F},
+ {0x246, 0x07, 0x07},
};
- struct sc_reg_access sc_access_amic[] = {
- /* turn on the audio power supplies */
- {0x0DB, 0x05, 0},
- /* VHSP */
- {0x0DC, 0xFF, 0},
- /* VHSN */
- {0x0DD, 0x3F, 0},
- /* turn on PLL */
- {0x240, 0x21, 0},
- /*ADC EN*/
- {0x248, 0x05, 0x0},
- {0x24C, 0x76, 0x0},
- /*MIC EN*/
- {0x249, 0x09, 0x0},
- {0x24A, 0x09, 0x0},
+ struct sc_reg_access amic_bias[] = {
/* Turn on AMIC supply */
- {0x247, 0xFC, 0x0},
+ {0x247, 0xFC, 0xFC},
+ };
+ struct sc_reg_access amic[] = {
+ /*MIC EN*/
+ {0x249, 0x01, 0x01},
+ {0x24A, 0x01, 0x01},
+ /*ADC EN*/
+ {0x248, 0x05, 0x0F},
};
- struct sc_reg_access sc_access2[] = {
+ struct sc_reg_access pcm2[] = {
/* enable pcm 2 */
{0x27C, 0x1, 0x1},
};
- struct sc_reg_access sc_access3[] = {
+ struct sc_reg_access tx_on[] = {
/*wait for mic to stabalize before turning on audio channels*/
{0x24F, 0x3C, 0x0},
};
@@ -271,42 +526,161 @@ static int msic_power_up_cp(unsigned int device)
}
pr_debug("powering up cp....%d\n", snd_msic_ops.input_dev_id);
- sst_sc_reg_access(sc_access2, PMIC_READ_MODIFY, 1);
+ sst_sc_reg_access(vaud, PMIC_WRITE, 1);
+ msleep(500);/*FIXME need optimzed value here*/
+ sst_sc_reg_access(pll, PMIC_WRITE, 1);
+ msleep(1);
snd_msic_ops.cap_on = 1;
- if (snd_msic_ops.input_dev_id == AMIC)
- sst_sc_reg_access(sc_access_amic, PMIC_WRITE, 9);
- else
- sst_sc_reg_access(sc_access, PMIC_WRITE, 9);
- return sst_sc_reg_access(sc_access3, PMIC_WRITE, 1);
-
+ if (snd_msic_ops.input_dev_id == AMIC) {
+ sst_sc_reg_access(amic_bias, PMIC_READ_MODIFY, 1);
+ msleep(1);
+ sst_sc_reg_access(amic, PMIC_READ_MODIFY, 3);
+ } else {
+ sst_sc_reg_access(dmic_bias, PMIC_READ_MODIFY, 1);
+ msleep(1);
+ sst_sc_reg_access(dmic, PMIC_READ_MODIFY, 2);
+ }
+ msleep(1);
+ sst_sc_reg_access(tx_on, PMIC_WRITE, 1);
+ return sst_sc_reg_access(pcm2, PMIC_READ_MODIFY, 1);
}
static int msic_power_down(void)
{
- int retval = 0;
+ struct sc_reg_access power_dn[] = {
+ /* VHSP */
+ {0x0DC, 0xC4, 0},
+ /* VHSN */
+ {0x0DD, 0x04, 0},
+ /* VIHF */
+ {0x0C9, 0x24, 0},
+ };
+ struct sc_reg_access pll[] = {
+ /* turn off PLL*/
+ {0x240, 0x00, 0x0},
+ };
+ struct sc_reg_access vaud[] = {
+ /* turn off VAUD*/
+ {0x0DB, 0x04, 0},
+ };
pr_debug("powering dn msic\n");
+ snd_msic_ops.pbhs_on = 0;
snd_msic_ops.pb_on = 0;
snd_msic_ops.cap_on = 0;
- return retval;
+ sst_sc_reg_access(power_dn, PMIC_WRITE, 3);
+ msleep(1);
+ sst_sc_reg_access(pll, PMIC_WRITE, 1);
+ msleep(1);
+ sst_sc_reg_access(vaud, PMIC_WRITE, 1);
+ return 0;
}
-static int msic_power_down_pb(void)
+static int msic_power_down_pb(unsigned int device)
{
- int retval = 0;
+ struct sc_reg_access drv_enable[] = {
+ {0x25D, 0x00, 0x00},
+ };
+ struct sc_reg_access hs_mute[] = {
+ {0x259, 0x80, 0x80},
+ {0x25A, 0x80, 0x80},
+ {0x26C, 0x02, 0x02},
+ };
+ struct sc_reg_access hs_off[] = {
+ {0x257, 0x00, 0x03},
+ {0x250, 0x00, 0x30},
+ {0x382, 0x00, 0x40},
+ };
+ struct sc_reg_access ihf_mute[] = {
+ {0x25B, 0x80, 0x80},
+ {0x25C, 0x80, 0x80},
+ };
+ struct sc_reg_access ihf_off[] = {
+ {0x257, 0x00, 0x0C},
+ {0x251, 0x00, 0x03},
+ };
+ struct sc_reg_access vib1_off[] = {
+ {0x264, 0x00, 0x82},
+ };
+ struct sc_reg_access vib2_off[] = {
+ {0x26A, 0x00, 0x82},
+ };
+ struct sc_reg_access lout_off[] = {
+ {0x25e, 0x66, 0x00},
+ };
+ struct sc_reg_access pmode_disable[] = {
+ {0x381, 0x00, 0x10},
+ };
- pr_debug("powering dn pb....\n");
- snd_msic_ops.pb_on = 0;
- return retval;
+
+
+ pr_debug("powering dn pb for device %d\n", device);
+ switch (device) {
+ case SND_SST_DEVICE_HEADSET:
+ snd_msic_ops.pbhs_on = 0;
+ sst_sc_reg_access(hs_mute, PMIC_READ_MODIFY, 3);
+ drv_enable[0].mask = 0x43;
+ sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1);
+ sst_sc_reg_access(hs_off, PMIC_READ_MODIFY, 3);
+ if (snd_msic_ops.lineout_dev_id == HEADSET)
+ sst_sc_reg_access(lout_off, PMIC_WRITE, 1);
+ break;
+
+ case SND_SST_DEVICE_IHF:
+ sst_sc_reg_access(ihf_mute, PMIC_READ_MODIFY, 2);
+ drv_enable[0].mask = 0x0C;
+ sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1);
+ sst_sc_reg_access(ihf_off, PMIC_READ_MODIFY, 2);
+ if (snd_msic_ops.lineout_dev_id == IHF) {
+ sst_sc_reg_access(lout_off, PMIC_WRITE, 1);
+ sst_sc_reg_access(pmode_disable, PMIC_READ_MODIFY, 1);
+ }
+ break;
+
+ case SND_SST_DEVICE_VIBRA:
+ sst_sc_reg_access(vib1_off, PMIC_READ_MODIFY, 1);
+ drv_enable[0].mask = 0x10;
+ sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1);
+ if (snd_msic_ops.lineout_dev_id == VIBRA1)
+ sst_sc_reg_access(lout_off, PMIC_WRITE, 1);
+ break;
+
+ case SND_SST_DEVICE_HAPTIC:
+ sst_sc_reg_access(vib2_off, PMIC_READ_MODIFY, 1);
+ drv_enable[0].mask = 0x20;
+ sst_sc_reg_access(drv_enable, PMIC_READ_MODIFY, 1);
+ if (snd_msic_ops.lineout_dev_id == VIBRA2)
+ sst_sc_reg_access(lout_off, PMIC_WRITE, 1);
+ break;
+ }
+ return 0;
}
-static int msic_power_down_cp(void)
+static int msic_power_down_cp(unsigned int device)
{
- int retval = 0;
+ struct sc_reg_access dmic[] = {
+ {0x247, 0x00, 0xA0},
+ {0x245, 0x00, 0x38},
+ {0x246, 0x00, 0x07},
+ };
+ struct sc_reg_access amic[] = {
+ {0x248, 0x00, 0x05},
+ {0x249, 0x00, 0x01},
+ {0x24A, 0x00, 0x01},
+ {0x247, 0x00, 0xA3},
+ };
+ struct sc_reg_access tx_off[] = {
+ {0x24F, 0x00, 0x3C},
+ };
pr_debug("powering dn cp....\n");
snd_msic_ops.cap_on = 0;
- return retval;
+ sst_sc_reg_access(tx_off, PMIC_READ_MODIFY, 1);
+ if (snd_msic_ops.input_dev_id == DMIC)
+ sst_sc_reg_access(dmic, PMIC_READ_MODIFY, 3);
+ else
+ sst_sc_reg_access(amic, PMIC_READ_MODIFY, 4);
+ return 0;
}
static int msic_set_selected_output_dev(u8 value)
@@ -315,7 +689,7 @@ static int msic_set_selected_output_dev(u8 value)
pr_debug("msic set selected output:%d\n", value);
snd_msic_ops.output_dev_id = value;
- if (snd_msic_ops.pb_on)
+ if (snd_msic_ops.pbhs_on)
msic_power_up_pb(SND_SST_DEVICE_HEADSET);
return retval;
}
@@ -352,6 +726,57 @@ static int msic_set_selected_input_dev(u8 value)
return retval;
}
+static int msic_set_hw_dmic_route(u8 hw_ch_index)
+{
+ struct sc_reg_access sc_access_router;
+ int retval = -EINVAL;
+
+ switch (hw_ch_index) {
+ case HW_CH0:
+ sc_access_router.reg_addr = AUDIOMUX12;
+ sc_access_router.value = snd_msic_ops.hw_dmic_map[0];
+ sc_access_router.mask = (MASK2 | MASK1 | MASK0);
+ pr_debug("hw_ch0. value = 0x%x\n",
+ sc_access_router.value);
+ retval = sst_sc_reg_access(&sc_access_router,
+ PMIC_READ_MODIFY, 1);
+ break;
+
+ case HW_CH1:
+ sc_access_router.reg_addr = AUDIOMUX12;
+ sc_access_router.value = (snd_msic_ops.hw_dmic_map[1]) << 4;
+ sc_access_router.mask = (MASK6 | MASK5 | MASK4);
+ pr_debug("### hw_ch1. value = 0x%x\n",
+ sc_access_router.value);
+ retval = sst_sc_reg_access(&sc_access_router,
+ PMIC_READ_MODIFY, 1);
+ break;
+
+ case HW_CH2:
+ sc_access_router.reg_addr = AUDIOMUX34;
+ sc_access_router.value = snd_msic_ops.hw_dmic_map[2];
+ sc_access_router.mask = (MASK2 | MASK1 | MASK0);
+ pr_debug("hw_ch2. value = 0x%x\n",
+ sc_access_router.value);
+ retval = sst_sc_reg_access(&sc_access_router,
+ PMIC_READ_MODIFY, 1);
+ break;
+
+ case HW_CH3:
+ sc_access_router.reg_addr = AUDIOMUX34;
+ sc_access_router.value = (snd_msic_ops.hw_dmic_map[3]) << 4;
+ sc_access_router.mask = (MASK6 | MASK5 | MASK4);
+ pr_debug("hw_ch3. value = 0x%x\n",
+ sc_access_router.value);
+ retval = sst_sc_reg_access(&sc_access_router,
+ PMIC_READ_MODIFY, 1);
+ break;
+ }
+
+ return retval;
+}
+
+
static int msic_set_pcm_voice_params(void)
{
return 0;
@@ -392,9 +817,215 @@ static int msic_get_vol(int dev_id, int *value)
return 0;
}
+static int msic_set_headset_state(int state)
+{
+ struct sc_reg_access hs_enable[] = {
+ {0x25D, 0x03, 0x03},
+ };
+
+ if (state)
+ /*enable*/
+ sst_sc_reg_access(hs_enable, PMIC_READ_MODIFY, 1);
+ else {
+ hs_enable[0].value = 0;
+ sst_sc_reg_access(hs_enable, PMIC_READ_MODIFY, 1);
+ }
+ return 0;
+}
+
+static int msic_enable_mic_bias(void)
+{
+ struct sc_reg_access jack_interrupt_reg[] = {
+ {0x0DB, 0x07, 0x00},
+
+ };
+ struct sc_reg_access jack_bias_reg[] = {
+ {0x247, 0x0C, 0x0C},
+ };
+
+ sst_sc_reg_access(jack_interrupt_reg, PMIC_WRITE, 1);
+ sst_sc_reg_access(jack_bias_reg, PMIC_READ_MODIFY, 1);
+ return 0;
+}
+
+static int msic_disable_mic_bias(void)
+{
+ if (snd_msic_ops.jack_interrupt_status == true)
+ return 0;
+ if (!(snd_msic_ops.pb_on || snd_msic_ops.cap_on))
+ msic_power_down();
+ return 0;
+}
+
+static int msic_disable_jack_btn(void)
+{
+ struct sc_reg_access btn_disable[] = {
+ {0x26C, 0x00, 0x01}
+ };
+
+ if (!(snd_msic_ops.pb_on || snd_msic_ops.cap_on))
+ msic_power_down();
+ snd_msic_ops.jack_interrupt_status = false;
+ return sst_sc_reg_access(btn_disable, PMIC_READ_MODIFY, 1);
+}
+
+static int msic_enable_jack_btn(void)
+{
+ struct sc_reg_access btn_enable[] = {
+ {0x26b, 0x77, 0x00},
+ {0x26C, 0x01, 0x00},
+ };
+ return sst_sc_reg_access(btn_enable, PMIC_WRITE, 2);
+}
+static int msic_convert_adc_to_mvolt(unsigned int mic_bias)
+{
+ return (ADC_ONE_LSB_MULTIPLIER * mic_bias) / 1000;
+}
+int msic_get_headset_state(int mic_bias)
+{
+ struct sc_reg_access msic_hs_toggle[] = {
+ {0x070, 0x00, 0x01},
+ };
+ if (mic_bias >= 0 && mic_bias < 400) {
+
+ pr_debug("Detected Headphone!!!\n");
+ sst_sc_reg_access(msic_hs_toggle, PMIC_READ_MODIFY, 1);
+
+ } else if (mic_bias > 400 && mic_bias < 650) {
+
+ pr_debug("Detected American headset\n");
+ msic_hs_toggle[0].value = 0x01;
+ sst_sc_reg_access(msic_hs_toggle, PMIC_READ_MODIFY, 1);
+
+ } else if (mic_bias >= 650 && mic_bias < 2000) {
+
+ pr_debug("Detected Headset!!!\n");
+ sst_sc_reg_access(msic_hs_toggle, PMIC_READ_MODIFY, 1);
+ /*power on jack and btn*/
+ snd_msic_ops.jack_interrupt_status = true;
+ msic_enable_jack_btn();
+ msic_enable_mic_bias();
+ return SND_JACK_HEADSET;
+
+ } else
+ pr_debug("Detected Open Cable!!!\n");
+
+ return SND_JACK_HEADPHONE;
+}
+
+static int msic_get_mic_bias(void *arg)
+{
+ struct snd_intelmad *intelmad_drv = (struct snd_intelmad *)arg;
+ u16 adc_adr = intelmad_drv->adc_address;
+ u16 adc_val;
+ int ret;
+ struct sc_reg_access adc_ctrl3[2] = {
+ {0x1C2, 0x05, 0x0},
+ };
+
+ struct sc_reg_access audio_adc_reg1 = {0,};
+ struct sc_reg_access audio_adc_reg2 = {0,};
+
+ msic_enable_mic_bias();
+ /* Enable the msic for conversion before reading */
+ ret = sst_sc_reg_access(adc_ctrl3, PMIC_WRITE, 1);
+ if (ret)
+ return ret;
+ adc_ctrl3[0].value = 0x04;
+ /* Re-toggle the RRDATARD bit */
+ ret = sst_sc_reg_access(adc_ctrl3, PMIC_WRITE, 1);
+ if (ret)
+ return ret;
+
+ audio_adc_reg1.reg_addr = adc_adr;
+ /* Read the higher bits of data */
+ msleep(1000);
+ ret = sst_sc_reg_access(&audio_adc_reg1, PMIC_READ, 1);
+ if (ret)
+ return ret;
+ pr_debug("adc read value %x", audio_adc_reg1.value);
+
+ /* Shift bits to accomodate the lower two data bits */
+ adc_val = (audio_adc_reg1.value << 2);
+ adc_adr++;
+ audio_adc_reg2. reg_addr = adc_adr;
+ ret = sst_sc_reg_access(&audio_adc_reg2, PMIC_READ, 1);
+ if (ret)
+ return ret;
+ pr_debug("adc read value %x", audio_adc_reg2.value);
+
+ /* Adding lower two bits to the higher bits */
+ audio_adc_reg2.value &= 03;
+ adc_val += audio_adc_reg2.value;
+
+ pr_debug("ADC value 0x%x", adc_val);
+ msic_disable_mic_bias();
+ return adc_val;
+}
+
+static void msic_pmic_irq_cb(void *cb_data, u8 intsts)
+{
+ struct mad_jack *mjack = NULL;
+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
+ struct snd_intelmad *intelmaddata = cb_data;
+ int retval = 0;
+
+ pr_debug("value returned = 0x%x\n", intsts);
+
+ if (snd_msic_ops.card_status == SND_CARD_UN_INIT) {
+ retval = msic_init_card();
+ if (retval)
+ return;
+ }
+
+ mjack = &intelmaddata->jack[0];
+ if (intsts & 0x1) {
+ pr_debug("MAD short_push detected\n");
+ present = SND_JACK_BTN_0;
+ jack_event_flag = buttonpressflag = 1;
+ mjack->jack.type = SND_JACK_BTN_0;
+ mjack->jack.key[0] = BTN_0 ;
+ }
+
+ if (intsts & 0x2) {
+ pr_debug(":MAD long_push detected\n");
+ jack_event_flag = buttonpressflag = 1;
+ mjack->jack.type = present = SND_JACK_BTN_1;
+ mjack->jack.key[1] = BTN_1;
+ }
+
+ if (intsts & 0x4) {
+ unsigned int mic_bias;
+ jack_event_flag = 1;
+ buttonpressflag = 0;
+ mic_bias = msic_get_mic_bias(intelmaddata);
+ pr_debug("mic_bias = %d\n", mic_bias);
+ mic_bias = msic_convert_adc_to_mvolt(mic_bias);
+ pr_debug("mic_bias after conversion = %d mV\n", mic_bias);
+ mjack->jack_dev_state = msic_get_headset_state(mic_bias);
+ mjack->jack.type = present = mjack->jack_dev_state;
+ }
+
+ if (intsts & 0x8) {
+ mjack->jack.type = mjack->jack_dev_state;
+ present = 0;
+ jack_event_flag = 1;
+ buttonpressflag = 0;
+ msic_disable_jack_btn();
+ msic_disable_mic_bias();
+ }
+ if (jack_event_flag)
+ sst_mad_send_jack_report(&mjack->jack,
+ buttonpressflag, present);
+}
+
+
+
struct snd_pmic_ops snd_msic_ops = {
.set_input_dev = msic_set_selected_input_dev,
.set_output_dev = msic_set_selected_output_dev,
+ .set_lineout_dev = msic_set_selected_lineout_dev,
+ .set_hw_dmic_route = msic_set_hw_dmic_route,
.set_mute = msic_set_mute,
.get_mute = msic_get_mute,
.set_vol = msic_set_vol,
@@ -408,5 +1039,9 @@ struct snd_pmic_ops snd_msic_ops = {
.power_up_pmic_cp = msic_power_up_cp,
.power_down_pmic_pb = msic_power_down_pb,
.power_down_pmic_cp = msic_power_down_cp,
- .power_down_pmic = msic_power_down,
+ .power_down_pmic = msic_power_down,
+ .pmic_irq_cb = msic_pmic_irq_cb,
+ .pmic_jack_enable = msic_enable_mic_bias,
+ .pmic_get_mic_bias = msic_get_mic_bias,
+ .pmic_set_headset_state = msic_set_headset_state,
};
diff --git a/drivers/staging/intel_sst/intelmid_pvt.c b/drivers/staging/intel_sst/intelmid_pvt.c
index 3ba9daf..90e0e64 100644
--- a/drivers/staging/intel_sst/intelmid_pvt.c
+++ b/drivers/staging/intel_sst/intelmid_pvt.c
@@ -31,7 +31,6 @@
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
-#include "jack.h"
#include "intel_sst.h"
#include "intel_sst_ioctl.h"
#include "intelmid_snd_control.h"
diff --git a/drivers/staging/intel_sst/intelmid_snd_control.h b/drivers/staging/intel_sst/intelmid_snd_control.h
index a4565f3..06ad3a1 100644
--- a/drivers/staging/intel_sst/intelmid_snd_control.h
+++ b/drivers/staging/intel_sst/intelmid_snd_control.h
@@ -80,6 +80,13 @@ enum SND_INPUT_DEVICE {
HS_MIC,
IN_UNDEFINED
};
+enum SND_LINE_OUT_DEVICE {
+ HEADSET,
+ IHF,
+ VIBRA1,
+ VIBRA2,
+ NONE,
+};
enum SND_OUTPUT_DEVICE {
STEREO_HEADPHONE,
@@ -104,6 +111,8 @@ enum pmic_controls {
PMIC_SND_RIGHT_SPEAKER_MUTE = 0x0015,
PMIC_SND_RECEIVER_VOL = 0x0016,
PMIC_SND_RECEIVER_MUTE = 0x0017,
+ PMIC_SND_LEFT_MASTER_VOL = 0x0018,
+ PMIC_SND_RIGHT_MASTER_VOL = 0x0019,
/* Other controls */
PMIC_SND_MUTE_ALL = 0x0020,
PMIC_MAX_CONTROLS = 0x0020,
diff --git a/drivers/staging/intel_sst/intelmid_v0_control.c b/drivers/staging/intel_sst/intelmid_v0_control.c
index 7756f8f..b8dfdb9 100644
--- a/drivers/staging/intel_sst/intelmid_v0_control.c
+++ b/drivers/staging/intel_sst/intelmid_v0_control.c
@@ -30,9 +30,10 @@
#include <linux/pci.h>
#include <linux/file.h>
+#include <sound/control.h>
#include "intel_sst.h"
#include "intelmid_snd_control.h"
-
+#include "intelmid.h"
enum _reg_v1 {
VOICEPORT1 = 0x180,
@@ -64,6 +65,7 @@ enum _reg_v1 {
};
int rev_id = 0x20;
+static bool jack_det_enabled;
/****
* fs_init_card - initialize the sound card
@@ -157,7 +159,7 @@ static int fs_power_up_pb(unsigned int port)
return fs_enable_audiodac(UNMUTE);
}
-static int fs_power_down_pb(void)
+static int fs_power_down_pb(unsigned int device)
{
struct sc_reg_access sc_access[] = {
{POWERCTRL1, 0x00, 0xC6},
@@ -195,7 +197,7 @@ static int fs_power_up_cp(unsigned int port)
return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
}
-static int fs_power_down_cp(void)
+static int fs_power_down_cp(unsigned int device)
{
struct sc_reg_access sc_access[] = {
{POWERCTRL2, 0x00, 0x03},
@@ -753,6 +755,90 @@ static int fs_get_vol(int dev_id, int *value)
return retval;
}
+static void fs_pmic_irq_enable(void *data)
+{
+ struct snd_intelmad *intelmaddata = data;
+ struct sc_reg_access sc_access[] = {
+ {0x187, 0x00, MASK7},
+ {0x188, 0x10, MASK4},
+ {0x18b, 0x10, MASK4},
+ };
+
+ struct sc_reg_access sc_access_write[] = {
+ {0x198, 0x00, 0x0},
+ };
+ pr_debug("Audio interrupt enable\n");
+ sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
+ sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1);
+
+ intelmaddata->jack[0].jack_status = 0;
+ /*intelmaddata->jack[1].jack_status = 0;*/
+
+ jack_det_enabled = true;
+ return;
+}
+
+static void fs_pmic_irq_cb(void *cb_data, u8 value)
+{
+ struct mad_jack *mjack = NULL;
+ struct snd_intelmad *intelmaddata = cb_data;
+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
+
+ mjack = &intelmaddata->jack[0];
+
+ if (value & 0x4) {
+ if (!jack_det_enabled)
+ fs_pmic_irq_enable(intelmaddata);
+
+ /* send headphone detect */
+ pr_debug(":MAD headphone %d\n", value & 0x4);
+ present = !(mjack->jack_status);
+ mjack->jack_status = present;
+ jack_event_flag = 1;
+ mjack->jack.type = SND_JACK_HEADPHONE;
+ }
+
+ if (value & 0x2) {
+ /* send short push */
+ pr_debug(":MAD short push %d\n", value & 0x2);
+ present = 1;
+ jack_event_flag = 1;
+ buttonpressflag = 1;
+ mjack->jack.type = MID_JACK_HS_SHORT_PRESS;
+ }
+
+ if (value & 0x1) {
+ /* send long push */
+ pr_debug(":MAD long push %d\n", value & 0x1);
+ present = 1;
+ jack_event_flag = 1;
+ buttonpressflag = 1;
+ mjack->jack.type = MID_JACK_HS_LONG_PRESS;
+ }
+
+ if (value & 0x8) {
+ if (!jack_det_enabled)
+ fs_pmic_irq_enable(intelmaddata);
+ /* send headset detect */
+ pr_debug(":MAD headset = %d\n", value & 0x8);
+ present = !(mjack->jack_status);
+ mjack->jack_status = present;
+ jack_event_flag = 1;
+ mjack->jack.type = SND_JACK_HEADSET;
+ }
+
+
+ if (jack_event_flag)
+ sst_mad_send_jack_report(&mjack->jack,
+ buttonpressflag, present);
+
+ return;
+}
+static int fs_jack_enable(void)
+{
+ return 0;
+}
+
struct snd_pmic_ops snd_pmic_ops_fs = {
.set_input_dev = fs_set_selected_input_dev,
.set_output_dev = fs_set_selected_output_dev,
@@ -765,9 +851,16 @@ struct snd_pmic_ops snd_pmic_ops_fs = {
.set_pcm_voice_params = fs_set_pcm_voice_params,
.set_voice_port = fs_set_voice_port,
.set_audio_port = fs_set_audio_port,
- .power_up_pmic_pb = fs_power_up_pb,
- .power_up_pmic_cp = fs_power_up_cp,
- .power_down_pmic_pb = fs_power_down_pb,
- .power_down_pmic_cp = fs_power_down_cp,
- .power_down_pmic = fs_power_down,
+ .power_up_pmic_pb = fs_power_up_pb,
+ .power_up_pmic_cp = fs_power_up_cp,
+ .power_down_pmic_pb = fs_power_down_pb,
+ .power_down_pmic_cp = fs_power_down_cp,
+ .power_down_pmic = fs_power_down,
+ .pmic_irq_cb = fs_pmic_irq_cb,
+ /*
+ * Jack detection enabling
+ * need be delayed till first IRQ happen.
+ */
+ .pmic_irq_enable = NULL,
+ .pmic_jack_enable = fs_jack_enable,
};
diff --git a/drivers/staging/intel_sst/intelmid_v1_control.c b/drivers/staging/intel_sst/intelmid_v1_control.c
index 1ea8142..9d00728 100644
--- a/drivers/staging/intel_sst/intelmid_v1_control.c
+++ b/drivers/staging/intel_sst/intelmid_v1_control.c
@@ -32,7 +32,6 @@
#include <linux/file.h>
#include <asm/mrst.h>
#include <sound/pcm.h>
-#include "jack.h"
#include <sound/pcm_params.h>
#include <sound/control.h>
#include <sound/initval.h>
@@ -212,7 +211,7 @@ static int mx_power_up_pb(unsigned int port)
return mx_enable_audiodac(UNMUTE);
}
-static int mx_power_down_pb(void)
+static int mx_power_down_pb(unsigned int device)
{
struct sc_reg_access sc_access[3];
int retval = 0;
@@ -255,7 +254,7 @@ static int mx_power_up_cp(unsigned int port)
return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
}
-static int mx_power_down_cp(void)
+static int mx_power_down_cp(unsigned int device)
{
struct sc_reg_access sc_access[] = {
{ENABLE_OPDEV_CTRL, 0x00, MASK1|MASK0},
@@ -832,6 +831,129 @@ static int mx_get_vol(int dev_id, int *value)
return retval;
}
+static u8 mx_get_jack_status(void)
+{
+ struct sc_reg_access sc_access_read = {0,};
+
+ sc_access_read.reg_addr = 0x201;
+ sst_sc_reg_access(&sc_access_read, PMIC_READ, 1);
+ pr_debug("value returned = 0x%x\n", sc_access_read.value);
+ return sc_access_read.value;
+}
+
+static void mx_pmic_irq_enable(void *data)
+{
+ struct snd_intelmad *intelmaddata = data;
+
+ intelmaddata->jack_prev_state = 0xc0;
+ return;
+}
+
+static void mx_pmic_irq_cb(void *cb_data, u8 intsts)
+{
+ u8 jack_cur_status, jack_prev_state = 0;
+ struct mad_jack *mjack = NULL;
+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
+ time_t timediff;
+ struct snd_intelmad *intelmaddata = cb_data;
+
+ mjack = &intelmaddata->jack[0];
+ if (intsts & 0x2) {
+ jack_cur_status = mx_get_jack_status();
+ jack_prev_state = intelmaddata->jack_prev_state;
+ if ((jack_prev_state == 0xc0) && (jack_cur_status == 0x40)) {
+ /*headset insert detected. */
+ pr_debug("MAD headset inserted\n");
+ present = 1;
+ jack_event_flag = 1;
+ mjack->jack_status = 1;
+ mjack->jack.type = SND_JACK_HEADSET;
+ }
+
+ if ((jack_prev_state == 0xc0) && (jack_cur_status == 0x00)) {
+ /* headphone insert detected. */
+ pr_debug("MAD headphone inserted\n");
+ present = 1;
+ jack_event_flag = 1;
+ mjack->jack.type = SND_JACK_HEADPHONE;
+ }
+
+ if ((jack_prev_state == 0x40) && (jack_cur_status == 0xc0)) {
+ /* headset remove detected. */
+ pr_debug("MAD headset removed\n");
+
+ present = 0;
+ jack_event_flag = 1;
+ mjack->jack_status = 0;
+ mjack->jack.type = SND_JACK_HEADSET;
+ }
+
+ if ((jack_prev_state == 0x00) && (jack_cur_status == 0xc0)) {
+ /* headphone remove detected. */
+ pr_debug("MAD headphone removed\n");
+ present = 0;
+ jack_event_flag = 1;
+ mjack->jack.type = SND_JACK_HEADPHONE;
+ }
+
+ if ((jack_prev_state == 0x40) && (jack_cur_status == 0x00)) {
+ /* button pressed */
+ do_gettimeofday(&mjack->buttonpressed);
+ pr_debug("MAD button press detected\n");
+ }
+
+ if ((jack_prev_state == 0x00) && (jack_cur_status == 0x40)) {
+ if (mjack->jack_status) {
+ /*button pressed */
+ do_gettimeofday(
+ &mjack->buttonreleased);
+ /*button pressed */
+ pr_debug("MAD Button Released detected\n");
+ timediff = mjack->buttonreleased.tv_sec -
+ mjack->buttonpressed.tv_sec;
+ buttonpressflag = 1;
+
+ if (timediff > 1) {
+ pr_debug("MAD long press dtd\n");
+ /* send headphone detect/undetect */
+ present = 1;
+ jack_event_flag = 1;
+ mjack->jack.type =
+ MID_JACK_HS_LONG_PRESS;
+ } else {
+ pr_debug("MAD short press dtd\n");
+ /* send headphone detect/undetect */
+ present = 1;
+ jack_event_flag = 1;
+ mjack->jack.type =
+ MID_JACK_HS_SHORT_PRESS;
+ }
+ } else {
+ /***workaround for maxim
+ hw issue,0x00 t 0x40 is not
+ a valid transiton for Headset insertion */
+ /*headset insert detected. */
+ pr_debug("MAD headset inserted\n");
+ present = 1;
+ jack_event_flag = 1;
+ mjack->jack_status = 1;
+ mjack->jack.type = SND_JACK_HEADSET;
+ }
+ }
+ intelmaddata->jack_prev_state = jack_cur_status;
+ pr_debug("mx_pmic_irq_cb prv_state= 0x%x\n",
+ intelmaddata->jack_prev_state);
+ }
+
+ if (jack_event_flag)
+ sst_mad_send_jack_report(&mjack->jack,
+ buttonpressflag, present);
+}
+static int mx_jack_enable(void)
+{
+ return 0;
+}
+
struct snd_pmic_ops snd_pmic_ops_mx = {
.set_input_dev = mx_set_selected_input_dev,
.set_output_dev = mx_set_selected_output_dev,
@@ -844,10 +966,13 @@ struct snd_pmic_ops snd_pmic_ops_mx = {
.set_pcm_voice_params = mx_set_pcm_voice_params,
.set_voice_port = mx_set_voice_port,
.set_audio_port = mx_set_audio_port,
- .power_up_pmic_pb = mx_power_up_pb,
- .power_up_pmic_cp = mx_power_up_cp,
- .power_down_pmic_pb = mx_power_down_pb,
- .power_down_pmic_cp = mx_power_down_cp,
- .power_down_pmic = mx_power_down,
+ .power_up_pmic_pb = mx_power_up_pb,
+ .power_up_pmic_cp = mx_power_up_cp,
+ .power_down_pmic_pb = mx_power_down_pb,
+ .power_down_pmic_cp = mx_power_down_cp,
+ .power_down_pmic = mx_power_down,
+ .pmic_irq_cb = mx_pmic_irq_cb,
+ .pmic_irq_enable = mx_pmic_irq_enable,
+ .pmic_jack_enable = mx_jack_enable,
};
diff --git a/drivers/staging/intel_sst/intelmid_v2_control.c b/drivers/staging/intel_sst/intelmid_v2_control.c
index 3c6b3ab..000378a 100644
--- a/drivers/staging/intel_sst/intelmid_v2_control.c
+++ b/drivers/staging/intel_sst/intelmid_v2_control.c
@@ -28,11 +28,14 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/gpio.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/file.h>
+#include <sound/control.h>
#include "intel_sst.h"
#include "intelmid_snd_control.h"
+#include "intelmid.h"
enum reg_v3 {
VAUDIOCNT = 0x51,
@@ -82,8 +85,15 @@ enum reg_v3 {
HPLMIXSEL = 0x12b,
HPRMIXSEL = 0x12c,
LOANTIPOP = 0x12d,
+ AUXDBNC = 0x12f,
};
+static void nc_set_amp_power(int power)
+{
+ if (snd_pmic_ops_nc.gpio_amp)
+ gpio_set_value(snd_pmic_ops_nc.gpio_amp, power);
+}
+
/****
* nc_init_card - initialize the sound card
*
@@ -111,18 +121,20 @@ static int nc_init_card(void)
{VOICEVOL, 0x0e, 0},
{HPLVOL, 0x06, 0},
{HPRVOL, 0x06, 0},
- {MICCTRL, 0x41, 0x00},
+ {MICCTRL, 0x51, 0x00},
{ADCSAMPLERATE, 0x8B, 0x00},
{MICSELVOL, 0x5B, 0x00},
{LILSEL, 0x06, 0},
{LIRSEL, 0x46, 0},
{LOANTIPOP, 0x00, 0},
{DMICCTRL1, 0x40, 0},
+ {AUXDBNC, 0xff, 0},
};
snd_pmic_ops_nc.card_status = SND_CARD_INIT_DONE;
snd_pmic_ops_nc.master_mute = UNMUTE;
snd_pmic_ops_nc.mute_status = UNMUTE;
- sst_sc_reg_access(sc_access, PMIC_WRITE, 26);
+ sst_sc_reg_access(sc_access, PMIC_WRITE, 27);
+ mutex_init(&snd_pmic_ops_nc.lock);
pr_debug("init complete!!\n");
return 0;
}
@@ -169,6 +181,7 @@ static int nc_power_up_pb(unsigned int port)
return retval;
if (port == 0xFF)
return 0;
+ mutex_lock(&snd_pmic_ops_nc.lock);
nc_enable_audiodac(MUTE);
msleep(30);
@@ -209,8 +222,21 @@ static int nc_power_up_pb(unsigned int port)
msleep(30);
- return nc_enable_audiodac(UNMUTE);
-
+ snd_pmic_ops_nc.pb_on = 1;
+
+ /*
+ * There is a mismatch between Playback Sources and the enumerated
+ * values of output sources. This mismatch causes ALSA upper to send
+ * Item 1 for Internal Speaker, but the expected enumeration is 2! For
+ * now, treat MONO_EARPIECE and INTERNAL_SPKR identically and power up
+ * the needed resources
+ */
+ if (snd_pmic_ops_nc.output_dev_id == MONO_EARPIECE ||
+ snd_pmic_ops_nc.output_dev_id == INTERNAL_SPKR)
+ nc_set_amp_power(1);
+ nc_enable_audiodac(UNMUTE);
+ mutex_unlock(&snd_pmic_ops_nc.lock);
+ return 0;
}
static int nc_power_up_cp(unsigned int port)
@@ -270,7 +296,6 @@ static int nc_power_down(void)
int retval = 0;
struct sc_reg_access sc_access[5];
-
if (snd_pmic_ops_nc.card_status == SND_CARD_UN_INIT)
retval = nc_init_card();
if (retval)
@@ -280,6 +305,10 @@ static int nc_power_down(void)
pr_debug("powering dn nc_power_down ....\n");
+ if (snd_pmic_ops_nc.output_dev_id == MONO_EARPIECE ||
+ snd_pmic_ops_nc.output_dev_id == INTERNAL_SPKR)
+ nc_set_amp_power(0);
+
msleep(30);
sc_access[0].reg_addr = DRVPOWERCTRL;
@@ -316,7 +345,7 @@ static int nc_power_down(void)
return nc_enable_audiodac(UNMUTE);
}
-static int nc_power_down_pb(void)
+static int nc_power_down_pb(unsigned int device)
{
int retval = 0;
@@ -328,7 +357,7 @@ static int nc_power_down_pb(void)
return retval;
pr_debug("powering dn pb....\n");
-
+ mutex_lock(&snd_pmic_ops_nc.lock);
nc_enable_audiodac(MUTE);
@@ -355,12 +384,14 @@ static int nc_power_down_pb(void)
msleep(30);
- return nc_enable_audiodac(UNMUTE);
-
+ snd_pmic_ops_nc.pb_on = 0;
+ nc_enable_audiodac(UNMUTE);
+ mutex_unlock(&snd_pmic_ops_nc.lock);
+ return 0;
}
-static int nc_power_down_cp(void)
+static int nc_power_down_cp(unsigned int device)
{
struct sc_reg_access sc_access[] = {
{POWERCTRL1, 0x00, 0xBE},
@@ -498,11 +529,13 @@ static int nc_set_selected_output_dev(u8 value)
{
struct sc_reg_access sc_access_HP[] = {
{LMUTE, 0x02, 0x06},
- {RMUTE, 0x02, 0x06}
+ {RMUTE, 0x02, 0x06},
+ {DRVPOWERCTRL, 0x06, 0x06},
};
struct sc_reg_access sc_access_IS[] = {
{LMUTE, 0x04, 0x06},
- {RMUTE, 0x04, 0x06}
+ {RMUTE, 0x04, 0x06},
+ {DRVPOWERCTRL, 0x00, 0x06},
};
int retval = 0;
@@ -512,17 +545,26 @@ static int nc_set_selected_output_dev(u8 value)
if (retval)
return retval;
pr_debug("nc set selected output:%d\n", value);
+ mutex_lock(&snd_pmic_ops_nc.lock);
switch (value) {
case STEREO_HEADPHONE:
+ if (snd_pmic_ops_nc.pb_on)
+ sst_sc_reg_access(sc_access_HP+2, PMIC_WRITE, 1);
retval = sst_sc_reg_access(sc_access_HP, PMIC_WRITE, 2);
+ nc_set_amp_power(0);
break;
+ case MONO_EARPIECE:
case INTERNAL_SPKR:
- retval = sst_sc_reg_access(sc_access_IS, PMIC_WRITE, 2);
+ retval = sst_sc_reg_access(sc_access_IS, PMIC_WRITE, 3);
+ if (snd_pmic_ops_nc.pb_on)
+ nc_set_amp_power(1);
break;
default:
pr_err("rcvd illegal request: %d\n", value);
+ mutex_unlock(&snd_pmic_ops_nc.lock);
return -EINVAL;
}
+ mutex_unlock(&snd_pmic_ops_nc.lock);
return retval;
}
@@ -784,9 +826,8 @@ static int nc_set_vol(int dev_id, int value)
case PMIC_SND_LEFT_PB_VOL:
pr_debug("PMIC_SND_LEFT_HP_VOL %d\n", value);
sc_access[0].value = -value;
- sc_access[0].reg_addr = AUDIOLVOL;
- sc_access[0].mask =
- (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
+ sc_access[0].reg_addr = HPLVOL;
+ sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
entries = 1;
break;
@@ -794,15 +835,32 @@ static int nc_set_vol(int dev_id, int value)
pr_debug("PMIC_SND_RIGHT_HP_VOL value %d\n", value);
if (snd_pmic_ops_nc.num_channel == 1) {
sc_access[0].value = 0x04;
- sc_access[0].reg_addr = RMUTE;
+ sc_access[0].reg_addr = RMUTE;
sc_access[0].mask = MASK2;
} else {
+ sc_access[0].value = -value;
+ sc_access[0].reg_addr = HPRVOL;
+ sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ }
+ entries = 1;
+ break;
+
+ case PMIC_SND_LEFT_MASTER_VOL:
+ pr_debug("PMIC_SND_LEFT_MASTER_VOL value %d\n", value);
+ sc_access[0].value = -value;
+ sc_access[0].reg_addr = AUDIOLVOL;
+ sc_access[0].mask =
+ (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
+ entries = 1;
+ break;
+
+ case PMIC_SND_RIGHT_MASTER_VOL:
+ pr_debug("PMIC_SND_RIGHT_MASTER_VOL value %d\n", value);
sc_access[0].value = -value;
- sc_access[0].reg_addr = AUDIORVOL;
+ sc_access[0].reg_addr = AUDIORVOL;
sc_access[0].mask =
(MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
entries = 1;
- }
break;
default:
@@ -831,7 +889,7 @@ static int nc_set_selected_input_dev(u8 value)
pr_debug("Selecting AMIC\n");
sc_access[0].reg_addr = 0x107;
sc_access[0].value = 0x40;
- sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0;
+ sc_access[0].mask = MASK6|MASK3|MASK1|MASK0;
sc_access[1].reg_addr = 0x10a;
sc_access[1].value = 0x40;
sc_access[1].mask = MASK6;
@@ -846,9 +904,9 @@ static int nc_set_selected_input_dev(u8 value)
case HS_MIC:
pr_debug("Selecting HS_MIC\n");
- sc_access[0].reg_addr = 0x107;
- sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0;
- sc_access[0].value = 0x10;
+ sc_access[0].reg_addr = MICCTRL;
+ sc_access[0].mask = MASK6|MASK3|MASK1|MASK0;
+ sc_access[0].value = 0x00;
sc_access[1].reg_addr = 0x109;
sc_access[1].mask = MASK6;
sc_access[1].value = 0x40;
@@ -858,13 +916,16 @@ static int nc_set_selected_input_dev(u8 value)
sc_access[3].reg_addr = 0x105;
sc_access[3].value = 0x40;
sc_access[3].mask = MASK6;
- num_val = 4;
+ sc_access[4].reg_addr = ADCSAMPLERATE;
+ sc_access[4].mask = MASK7|MASK6|MASK5|MASK4|MASK3;
+ sc_access[4].value = 0xc8;
+ num_val = 5;
break;
case DMIC:
pr_debug("DMIC\n");
- sc_access[0].reg_addr = 0x107;
- sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0;
+ sc_access[0].reg_addr = MICCTRL;
+ sc_access[0].mask = MASK6|MASK3|MASK1|MASK0;
sc_access[0].value = 0x0B;
sc_access[1].reg_addr = 0x105;
sc_access[1].value = 0x80;
@@ -872,12 +933,12 @@ static int nc_set_selected_input_dev(u8 value)
sc_access[2].reg_addr = 0x10a;
sc_access[2].value = 0x40;
sc_access[2].mask = MASK6;
- sc_access[3].reg_addr = 0x109;
+ sc_access[3].reg_addr = LILSEL;
sc_access[3].mask = MASK6;
sc_access[3].value = 0x00;
- sc_access[4].reg_addr = 0x104;
- sc_access[4].value = 0x3C;
- sc_access[4].mask = 0xff;
+ sc_access[4].reg_addr = ADCSAMPLERATE;
+ sc_access[4].mask = MASK7|MASK6|MASK5|MASK4|MASK3;
+ sc_access[4].value = 0x33;
num_val = 5;
break;
default:
@@ -964,18 +1025,30 @@ static int nc_get_vol(int dev_id, int *value)
mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
break;
- case PMIC_SND_RIGHT_PB_VOL:
- pr_debug("GET_VOLUME_PMIC_LEFT_HP_VOL\n");
+ case PMIC_SND_LEFT_MASTER_VOL:
+ pr_debug("GET_VOLUME_PMIC_LEFT_MASTER_VOL\n");
sc_access.reg_addr = AUDIOLVOL;
mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
break;
- case PMIC_SND_LEFT_PB_VOL:
- pr_debug("GET_VOLUME_PMIC_RIGHT_HP_VOL\n");
+ case PMIC_SND_RIGHT_MASTER_VOL:
+ pr_debug("GET_VOLUME_PMIC_RIGHT_MASTER_VOL\n");
sc_access.reg_addr = AUDIORVOL;
mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
break;
+ case PMIC_SND_RIGHT_PB_VOL:
+ pr_debug("GET_VOLUME_PMIC_RIGHT_HP_VOL\n");
+ sc_access.reg_addr = HPRVOL;
+ mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ break;
+
+ case PMIC_SND_LEFT_PB_VOL:
+ pr_debug("GET_VOLUME_PMIC_LEFT_HP_VOL\n");
+ sc_access.reg_addr = HPLVOL;
+ mask = (MASK0|MASK1|MASK2|MASK3|MASK4);
+ break;
+
default:
return -EINVAL;
@@ -987,7 +1060,81 @@ static int nc_get_vol(int dev_id, int *value)
return retval;
}
+static void hp_automute(enum snd_jack_types type, int present)
+{
+ u8 in = DMIC;
+ u8 out = INTERNAL_SPKR;
+ if (present) {
+ if (type == SND_JACK_HEADSET)
+ in = HS_MIC;
+ out = STEREO_HEADPHONE;
+ }
+ nc_set_selected_input_dev(in);
+ nc_set_selected_output_dev(out);
+}
+
+static void nc_pmic_irq_cb(void *cb_data, u8 intsts)
+{
+ u8 value = 0;
+ struct mad_jack *mjack = NULL;
+ unsigned int present = 0, jack_event_flag = 0, buttonpressflag = 0;
+ struct snd_intelmad *intelmaddata = cb_data;
+ struct sc_reg_access sc_access_read = {0,};
+
+ sc_access_read.reg_addr = 0x132;
+ sst_sc_reg_access(&sc_access_read, PMIC_READ, 1);
+ value = (sc_access_read.value);
+ pr_debug("value returned = 0x%x\n", value);
+
+ mjack = &intelmaddata->jack[0];
+ if (intsts & 0x1) {
+ pr_debug("SST DBG:MAD headset detected\n");
+ /* send headset detect/undetect */
+ present = (value == 0x1) ? 1 : 0;
+ jack_event_flag = 1;
+ mjack->jack.type = SND_JACK_HEADSET;
+ hp_automute(SND_JACK_HEADSET, present);
+ }
+
+ if (intsts & 0x2) {
+ pr_debug(":MAD headphone detected\n");
+ /* send headphone detect/undetect */
+ present = (value == 0x2) ? 1 : 0;
+ jack_event_flag = 1;
+ mjack->jack.type = SND_JACK_HEADPHONE;
+ hp_automute(SND_JACK_HEADPHONE, present);
+ }
+
+ if (intsts & 0x4) {
+ pr_debug("MAD short push detected\n");
+ /* send short push */
+ present = 1;
+ jack_event_flag = 1;
+ buttonpressflag = 1;
+ mjack->jack.type = MID_JACK_HS_SHORT_PRESS;
+ }
+
+ if (intsts & 0x8) {
+ pr_debug(":MAD long push detected\n");
+ /* send long push */
+ present = 1;
+ jack_event_flag = 1;
+ buttonpressflag = 1;
+ mjack->jack.type = MID_JACK_HS_LONG_PRESS;
+ }
+
+ if (jack_event_flag)
+ sst_mad_send_jack_report(&mjack->jack,
+ buttonpressflag, present);
+}
+static int nc_jack_enable(void)
+{
+ return 0;
+}
+
struct snd_pmic_ops snd_pmic_ops_nc = {
+ .input_dev_id = DMIC,
+ .output_dev_id = INTERNAL_SPKR,
.set_input_dev = nc_set_selected_input_dev,
.set_output_dev = nc_set_selected_output_dev,
.set_mute = nc_set_mute,
@@ -1003,5 +1150,7 @@ struct snd_pmic_ops snd_pmic_ops_nc = {
.power_up_pmic_cp = nc_power_up_cp,
.power_down_pmic_pb = nc_power_down_pb,
.power_down_pmic_cp = nc_power_down_cp,
- .power_down_pmic = nc_power_down,
+ .power_down_pmic = nc_power_down,
+ .pmic_irq_cb = nc_pmic_irq_cb,
+ .pmic_jack_enable = nc_jack_enable,
};
diff --git a/drivers/staging/intel_sst/jack.h b/drivers/staging/intel_sst/jack.h
deleted file mode 100644
index 9a6e483..0000000
--- a/drivers/staging/intel_sst/jack.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* Temporary staging glue */
-
-#include <sound/jack.h>
-
-/* These want adding to jack.h as enum entries once approved */
-
-#define SND_JACK_HS_SHORT_PRESS (SND_JACK_HEADSET | 0x0020)
-#define SND_JACK_HS_LONG_PRESS (SND_JACK_HEADSET | 0x0040)
-
-