#include <linux/sensor-dev.h>
#include <linux/mfd/tps65910.h>
#include <linux/regulator/rk29-pwm-regulator.h>
+#if defined(CONFIG_MODEM_SOUND)
+#include "../../../drivers/misc/modem_sound.h"
+#endif
#if defined(CONFIG_HDMI_RK30)
#include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h"
#endif
+#include "../../../drivers/headset_observe/rk_headset.h"
#if defined(CONFIG_SPIM_RK29)
#include "../../../drivers/spi/rk29_spim.h"
.batt_low_pin = INVALID_GPIO,
.charge_set_pin = INVALID_GPIO,
.charge_ok_pin = RK2928_PIN1_PA0,
- .dc_det_level = GPIO_LOW, //
+ .dc_det_level = GPIO_HIGH, //
.charge_ok_level = GPIO_HIGH,
};
},
};
#endif
+
+#if defined(CONFIG_MODEM_SOUND)
+
+struct modem_sound_data modem_sound_info = {
+ .spkctl_io = RK2928_PIN3_PD4,
+ .spkctl_active = GPIO_HIGH,
+};
+
+struct platform_device modem_sound_device = {
+ .name = "modem_sound",
+ .id = -1,
+ .dev = {
+ .platform_data = &modem_sound_info,
+ }
+ };
+#endif
/**************************************************************************************************
* SDMMC devices, include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05
**************************************************************************************************/
}
};
#endif
+#if defined (CONFIG_RK_HEADSET_DET) || defined (CONFIG_RK_HEADSET_IRQ_HOOK_ADC_DET)
+static int rk_headset_io_init(int gpio, char *iomux_name, int iomux_mode)
+{
+ int ret;
+ ret = gpio_request(gpio, "headset_io");
+ if(ret)
+ return ret;
+
+ rk30_mux_api_set(iomux_name, iomux_mode);
+ gpio_pull_updown(gpio, PullDisable);
+ gpio_direction_input(gpio);
+ mdelay(50);
+ return 0;
+};
+
+static int rk_hook_io_init(int gpio, char *iomux_name, int iomux_mode)
+{
+ int ret;
+ ret = gpio_request(gpio, "hook_io");
+ if(ret)
+ return ret;
+
+ rk30_mux_api_set(iomux_name, iomux_mode);
+ gpio_pull_updown(gpio, PullDisable);
+ gpio_direction_input(gpio);
+ mdelay(50);
+ return 0;
+};
+
+struct rk_headset_pdata rk_headset_info = {
+ .Headset_gpio = RK2928_PIN1_PB4,
+ .Hook_gpio = RK2928_PIN0_PD1,
+ .headset_in_type = HEADSET_IN_HIGH,
+ .hook_key_code = KEY_MEDIA,
+ .headset_gpio_info = {GPIO1B4_SPI_CSN1_NAME, GPIO1B_GPIO1B4},
+ .headset_io_init = rk_headset_io_init,
+ .hook_gpio_info = {GPIO0D1_UART2_CTSN_NAME, GPIO0D_GPIO0D1},
+ .hook_io_init = rk_hook_io_init,
+};
+struct platform_device rk_device_headset = {
+ .name = "rk_headsetdet",
+ .id = 0,
+ .dev = {
+ .platform_data = &rk_headset_info,
+ }
+};
+#endif
#ifdef CONFIG_SND_SOC_RK2928
static struct resource resources_acodec[] = {
{
&rk29_device_sc6610,
#endif
+#if defined (CONFIG_RK_HEADSET_DET) || defined (CONFIG_RK_HEADSET_IRQ_HOOK_ADC_DET)
+ &rk_device_headset,
+#endif
+#if defined (CONFIG_MODEM_SOUND)
+ &modem_sound_device,
+#endif
};
//i2c
#ifdef CONFIG_I2C0_RK30
#define enable 1
#define disable 0
-
+#ifdef CONFIG_SND_RK_SOC_RK2928
+extern void rk2928_codec_set_spk(bool on);
+#endif
#ifdef CONFIG_SND_SOC_WM8994
extern int wm8994_set_status(void);
#endif
}
EXPORT_SYMBOL_GPL(Headset_isMic);
+int Headset_status(void)
+{
+ if(headset_info->cur_headset_status == BIT_HEADSET_NO_MIC ||
+ headset_info->cur_headset_status == BIT_HEADSET )
+ return HEADSET_IN;
+ else
+ return HEADSET_OUT;
+}
+EXPORT_SYMBOL_GPL(Headset_status);
+
static irqreturn_t headset_interrupt(int irq, void *dev_id)
{
DBG("---headset_interrupt---\n");
disable_irq(headset_info->irq[HOOK]);
}
headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
+ #ifdef CONFIG_SND_RK_SOC_RK2928
+ rk2928_codec_set_spk(HEADSET_OUT);
+ #endif
headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);//
rk28_send_wakeup_key();
switch_set_state(&headset_info->sdev, headset_info->cur_headset_status);
DBG("disable headset_hook irq\n");
headset_info->isHook_irq = disable;
disable_irq(headset_info->irq[HOOK]);
- }
+ }
+ #ifdef CONFIG_SND_RK_SOC_RK2928
+ rk2928_codec_set_spk(HEADSET_OUT);
+ #endif
headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);//
rk28_send_wakeup_key();
headset_info->cur_headset_status = BIT_HEADSET;
printk("headset->isMic = %d\n",headset->isMic);
}
-
+ #ifdef CONFIG_SND_RK_SOC_RK2928
+ rk2928_codec_set_spk(HEADSET_IN);
+ #endif
rk28_send_wakeup_key();
switch_set_state(&headset_info->sdev, headset_info->cur_headset_status);
DBG("headset_info->cur_headset_status = %d\n",headset_info->cur_headset_status);
//------------------------------------------------------------------
if (pdata->Headset_gpio) {
- ret = gpio_request(pdata->Headset_gpio, NULL);
+ ret = pdata->headset_io_init(pdata->Headset_gpio, pdata->headset_gpio_info.iomux_name, pdata->headset_gpio_info.iomux_mode);
if (ret)
- goto failed_free_dev;
- gpio_pull_updown(pdata->Headset_gpio, PullDisable);
- gpio_direction_input(pdata->Headset_gpio);
+ goto failed_free;
+
headset->irq[HEADSET] = gpio_to_irq(pdata->Headset_gpio);
if(pdata->headset_in_type == HEADSET_IN_HIGH)
goto failed_free_dev;
//------------------------------------------------------------------
if (pdata->Hook_gpio) {
- ret = gpio_request(pdata->Hook_gpio , NULL);
+ ret = pdata->hook_io_init(pdata->Hook_gpio, pdata->hook_gpio_info.iomux_name, pdata->hook_gpio_info.iomux_mode);
if (ret)
- goto failed_free_dev;
- gpio_pull_updown(pdata->Hook_gpio, PullDisable);
- gpio_direction_input(pdata->Hook_gpio);
+ goto failed_free;
headset->irq[HOOK] = gpio_to_irq(pdata->Hook_gpio);
headset->irq_type[HOOK] = IRQF_TRIGGER_FALLING;
config TDSC8800
bool "TDSC8800 modem control driver"
default n
+config MODEM_SOUND
+ bool "modem sound control driver"
+ default n
+
source "drivers/misc/c2port/Kconfig"
obj-$(CONFIG_TDSC8800) += tdsc8800.o
obj-$(CONFIG_RK29_SC8800) += sc8800.o
obj-y += rk2928_callpad_misc/
+obj-$(CONFIG_MODEM_SOUND) += modem_sound.o
--- /dev/null
+#include <linux/input.h>\r
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/kernel.h>\r
+#include <linux/fcntl.h>\r
+#include <linux/delay.h>\r
+#include <linux/device.h>\r
+#include <linux/miscdevice.h>\r
+#include <asm/types.h>\r
+#include <mach/gpio.h>\r
+#include <mach/iomux.h>\r
+#include <linux/platform_device.h>\r
+#include <asm/uaccess.h>\r
+#include <linux/wait.h>\r
+#include "modem_sound.h"\r
+#if 1\r
+#define DBG(x...) printk(KERN_INFO x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+#define MODEM_EARPHOEN 0 //ÌýͲµç»°\r
+#define MODEM_HANDFREE 1 //ÃâÌá\r
+#define MODEM_HPPHONE 2 //¶ú»úµç»°\r
+#define MODEM_BTPHONE 3 //À¶ÑÀµç»°\r
+#define MODEM_STOP_PHONE 4 //ֹͣͨ»°\r
+\r
+#define ENABLE 1\r
+#define DISABLE 0\r
+\r
+static struct modem_sound_data *modem_sound;\r
+#ifdef CONFIG_SND_RK_SOC_RK2928\r
+extern void call_set_spk(bool on);\r
+#endif\r
+int modem_sound_spkctl(int status)\r
+{\r
+ if(status == ENABLE)\r
+ gpio_direction_output(modem_sound->spkctl_io,GPIO_HIGH);//modem_sound->spkctl_io? GPIO_HIGH:GPIO_LOW);\r
+ else \r
+ gpio_direction_output(modem_sound->spkctl_io,GPIO_LOW); //modem_sound->spkctl_io? GPIO_LOW:GPIO_HIGH);\r
+ \r
+ return 0;\r
+}\r
+\r
+static void modem_sound_delay_power_downup(struct work_struct *work)\r
+{\r
+ struct modem_sound_data *pdata = container_of(work, struct modem_sound_data, work);\r
+ if (pdata == NULL) {\r
+ printk("%s: pdata = NULL\n", __func__);\r
+ return;\r
+ }\r
+\r
+ down(&pdata->power_sem);\r
+ up(&pdata->power_sem);\r
+}\r
+\r
+static int modem_sound_open(struct inode *inode, struct file *filp)\r
+{\r
+ DBG("modem_sound_open\n");\r
+\r
+ return 0;\r
+}\r
+\r
+static ssize_t modem_sound_read(struct file *filp, char __user *ptr, size_t size, loff_t *pos)\r
+{\r
+ if (ptr == NULL)\r
+ printk("%s: user space address is NULL\n", __func__);\r
+ return sizeof(int);\r
+}\r
+\r
+static long modem_sound_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)\r
+{\r
+ long ret = 0;\r
+ struct modem_sound_data *pdata = modem_sound;\r
+\r
+ DBG("modem_sound_ioctl: cmd = %d arg = %ld\n",cmd, arg);\r
+\r
+ ret = down_interruptible(&pdata->power_sem);\r
+ if (ret < 0) {\r
+ printk("%s: down power_sem error ret = %ld\n", __func__, ret);\r
+ return ret;\r
+ }\r
+\r
+ switch (cmd){\r
+ case MODEM_EARPHOEN:\r
+ DBG("modem_sound_ioctl: MODEM_EAR_PHONE\n");\r
+ call_set_spk(0);\r
+ modem_sound_spkctl(DISABLE);\r
+ break;\r
+ case MODEM_HANDFREE:\r
+ DBG("modem_sound_ioctl: MODEM_SPK_PHONE\n");\r
+ call_set_spk(0);\r
+ modem_sound_spkctl(ENABLE);\r
+ break;\r
+ case MODEM_HPPHONE:\r
+ DBG("modem_sound_ioctl: MODEM_HP_PHONE\n");\r
+ call_set_spk(0);\r
+ modem_sound_spkctl(DISABLE);\r
+ break;\r
+ \r
+ case MODEM_BTPHONE:\r
+ call_set_spk(0);\r
+ modem_sound_spkctl(DISABLE);\r
+ DBG("modem_sound_ioctl: MODEM_BT_PHONE\n");\r
+ break;\r
+ case MODEM_STOP_PHONE:\r
+ DBG("modem_sound_ioctl: MODEM_STOP_PHONE\n");\r
+ call_set_spk(1);\r
+ break;\r
+\r
+ default:\r
+ printk("unknown ioctl cmd!\n");\r
+ up(&pdata->power_sem);\r
+ ret = -EINVAL;\r
+ break;\r
+ }\r
+\r
+ up(&pdata->power_sem);\r
+\r
+ return ret;\r
+}\r
+\r
+static int modem_sound_release(struct inode *inode, struct file *filp)\r
+{\r
+ DBG("modem_sound_release\n");\r
+ \r
+ return 0;\r
+}\r
+\r
+static struct file_operations modem_sound_fops = {\r
+ .owner = THIS_MODULE,\r
+ .open = modem_sound_open,\r
+ .read = modem_sound_read,\r
+ .unlocked_ioctl = modem_sound_ioctl,\r
+ .release = modem_sound_release,\r
+};\r
+\r
+static struct miscdevice modem_sound_dev = \r
+{\r
+ .minor = MISC_DYNAMIC_MINOR,\r
+ .name = "modem_sound",\r
+ .fops = &modem_sound_fops,\r
+};\r
+\r
+static int modem_sound_probe(struct platform_device *pdev)\r
+{\r
+ int ret = 0;\r
+ struct modem_sound_data *pdata = pdev->dev.platform_data;\r
+ if(!pdata)\r
+ return -1;\r
+ \r
+ ret = misc_register(&modem_sound_dev);\r
+ if (ret < 0){\r
+ printk("modem register err!\n");\r
+ return ret;\r
+ }\r
+ \r
+ sema_init(&pdata->power_sem,1);\r
+ pdata->wq = create_freezable_workqueue("modem_sound");\r
+ INIT_WORK(&pdata->work, modem_sound_delay_power_downup);\r
+ modem_sound = pdata;\r
+ printk("%s:modem sound initialized\n",__FUNCTION__);\r
+\r
+ return ret;\r
+}\r
+\r
+static int modem_sound_suspend(struct platform_device *pdev, pm_message_t state)\r
+{\r
+ struct modem_sound_data *pdata = pdev->dev.platform_data;\r
+\r
+ if(!pdata) {\r
+ printk("%s: pdata = NULL ...... \n", __func__);\r
+ return -1;\r
+ }\r
+ printk("%s\n",__FUNCTION__);\r
+ return 0; \r
+}\r
+\r
+static int modem_sound_resume(struct platform_device *pdev)\r
+{\r
+ struct modem_sound_data *pdata = pdev->dev.platform_data;\r
+\r
+ if(!pdata) {\r
+ printk("%s: pdata = NULL ...... \n", __func__);\r
+ return -1;\r
+ }\r
+ printk("%s\n",__FUNCTION__);\r
+ return 0;\r
+}\r
+\r
+static int modem_sound_remove(struct platform_device *pdev)\r
+{\r
+ struct modem_sound_data *pdata = pdev->dev.platform_data;\r
+ if(!pdata)\r
+ return -1;\r
+\r
+ misc_deregister(&modem_sound_dev);\r
+\r
+ return 0;\r
+}\r
+\r
+static struct platform_driver modem_sound_driver = {\r
+ .probe = modem_sound_probe,\r
+ .remove = modem_sound_remove,\r
+ .suspend = modem_sound_suspend,\r
+ .resume = modem_sound_resume,\r
+ .driver = {\r
+ .name = "modem_sound",\r
+ .owner = THIS_MODULE,\r
+ },\r
+};\r
+\r
+static int __init modem_sound_init(void)\r
+{\r
+ return platform_driver_register(&modem_sound_driver);\r
+}\r
+\r
+static void __exit modem_sound_exit(void)\r
+{\r
+ platform_driver_unregister(&modem_sound_driver);\r
+}\r
+\r
+module_init(modem_sound_init);\r
+module_exit(modem_sound_exit);\r
+MODULE_DESCRIPTION ("modem sound driver");\r
+MODULE_LICENSE("GPL");\r
+\r
--- /dev/null
+\r
+#ifndef __MODEM_SOUND_H__\r
+#define __MODEM_SOUND_H__\r
+\r
+struct modem_sound_data {\r
+ int spkctl_io;\r
+ int spkctl_active;\r
+ int codec_flag;\r
+ struct semaphore power_sem;\r
+ struct workqueue_struct *wq;\r
+ struct work_struct work;\r
+};\r
+\r
+#endif\r
#include <linux/clk.h>
#include "rk2928_codec.h"
+#define HP_OUT 0
+#define HP_IN 1
+
static struct rk2928_codec_data {
struct device *dev;
+ struct snd_soc_codec *codec;
int regbase;
int regbase_phy;
int regsize_phy;
int mute;
int hdmi_enable;
int spkctl;
+ int call_enable;
+ int headset_status;
} rk2928_data;
static const struct snd_soc_dapm_widget rk2928_dapm_widgets[] = {
rk2928_write(NULL, CODEC_REG_DAC_MUTE, v_MUTE_DAC(0));
}
}
+#ifdef CONFIG_MODEM_SOUND
+void call_set_spk(bool on)
+{
+ if(on == 0) {
+ printk("%s speaker is disabled\n", __FUNCTION__);
+ rk2928_data.call_enable = 1;
+ rk2928_write(NULL, CODEC_REG_DAC_MUTE, v_MUTE_DAC(1));
+ }
+ else {
+ printk("%s speaker is enabled\n", __FUNCTION__);
+ rk2928_data.call_enable = 0;
+ rk2928_write(NULL, CODEC_REG_DAC_MUTE, v_MUTE_DAC(0));
+ }
+}
+#endif
+#ifdef CONFIG_RK_HEADSET_DET
+//for headset
+void rk2928_codec_set_spk(bool on)
+{
+ struct snd_soc_codec *codec = rk2928_data.codec;
+
+ printk("%s: headset %s %s PA bias_level=%d\n",__FUNCTION__,on?"in":"out",on?"disable":"enable",codec->dapm.bias_level);
+ if(on) {
+ rk2928_data.headset_status = HP_IN;
+ if(rk2928_data.spkctl != INVALID_GPIO)
+ gpio_direction_output(rk2928_data.spkctl, GPIO_LOW);
+ }
+ else {
+ rk2928_data.headset_status = HP_OUT;
+ if(codec->dapm.bias_level == SND_SOC_BIAS_STANDBY
+ || codec->dapm.bias_level == SND_SOC_BIAS_OFF){
+ return;
+ }
+ if(rk2928_data.spkctl != INVALID_GPIO)
+ gpio_direction_output(rk2928_data.spkctl, GPIO_HIGH);
+ }
+}
+#endif
static int rk2928_audio_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
int err = 0;
int data, pd_adc;
DBG("%s cmd 0x%x", __FUNCTION__, cmd);
-
+#ifdef CONFIG_MODEM_SOUND
+ if(rk2928_data.call_enable)
+ return err;
+#endif
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(0));
}
rk2928_data.mute = 0;
- if(rk2928_data.spkctl != INVALID_GPIO) {
+ if(rk2928_data.spkctl != INVALID_GPIO && rk2928_data.headset_status == HP_OUT) {
gpio_direction_output(rk2928_data.spkctl, GPIO_HIGH);
}
}
static int rk2928_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- DBG("%s level %d", __FUNCTION__, level);
+ DBG("%s level %d\n", __FUNCTION__, level);
if(codec == NULL)
return -1;
else {
rk2928_data.spkctl = res->start;
}
-
+
if(rk2928_data.spkctl != INVALID_GPIO) {
ret = gpio_request(rk2928_data.spkctl, NULL);
if (ret != 0) {
else
gpio_direction_output(rk2928_data.spkctl, GPIO_LOW);
}
-
+
// Select SDI input from internal audio codec
writel(0x04000400, RK2928_GRF_BASE + GRF_SOC_CON0);
snd_soc_dapm_add_routes(dapm, rk2926_audio_map, ARRAY_SIZE(rk2926_audio_map));
}
+ rk2928_data.call_enable = 0;
+ rk2928_data.headset_status = HP_OUT;
+ rk2928_data.codec=codec;
return 0;
err1: