From f23c04fcddf3f8332ab7cf77121757817ac2e1fa Mon Sep 17 00:00:00 2001 From: "KP, Jeeja" Date: Tue, 13 Mar 2012 04:55:33 +0530 Subject: [PATCH] audio: Enable Vibra for CTP BZ: 27048 Added Vibra Driver for enabling Vibra on CTP. PWM generator is in the Cloverview SOC. Before turn off clock for audio fabric the PWM generator must be disabled. Vibra driver will be registered as the PCI device for Handling the PM.Currently the PCI_ID for vibra driver is not yet released. This patch will have workaround to configure the PWM generator as part of SST driver. This will be Fixed when IFWI with PCI for vibra is released. Change-Id: I65d77dd2d87bc9373926b39943c5193fc438ca62 Signed-off-by: KP, Jeeja Reviewed-on: http://android.intel.com:8080/38378 Reviewed-by: Koskinen, Ilkka Reviewed-by: Koul, Vinod Reviewed-by: Gupta, ArvindX K Reviewed-by: M, Arulselvan Tested-by: M, Arulselvan Reviewed-by: buildbot Tested-by: buildbot --- arch/x86/platform/intel-mid/board-ctp.c | 13 ++ drivers/input/misc/Kconfig | 10 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/intel_mid_vibra.c | 247 ++++++++++++++++++++++++++++++++ include/sound/intel_sst.h | 1 + sound/pci/sst/intel_sst.c | 58 +++++++- sound/pci/sst/intel_sst_common.h | 14 ++ 7 files changed, 343 insertions(+), 1 deletion(-) create mode 100644 drivers/input/misc/intel_mid_vibra.c diff --git a/arch/x86/platform/intel-mid/board-ctp.c b/arch/x86/platform/intel-mid/board-ctp.c index 49700c6..389966c 100644 --- a/arch/x86/platform/intel-mid/board-ctp.c +++ b/arch/x86/platform/intel-mid/board-ctp.c @@ -731,6 +731,19 @@ static void *clvcs_audio_platform_data(void *info) return NULL; } + pdev = platform_device_alloc("intel_mid_vibra", -1); + if (!pdev) { + pr_err("failed to allocate audio vibra device\n"); + return NULL; + } + + ret = platform_device_add(pdev); + if (ret) { + pr_err("failed to add audio vibra device\n"); + platform_device_put(pdev); + return NULL; + } + pdev = platform_device_alloc("hdmi-audio", -1); if (!pdev) { pr_err("failed to allocate hdmi-audio platform device\n"); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 6f4ad1a..c1689cb 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -286,6 +286,16 @@ config INPUT_TWL4030_VIBRA To compile this driver as a module, choose M here. The module will be called twl4030_vibra. +config INPUT_INTEL_MID_VIBRA + tristate "Support for Intel MID Vibrator" + depends on SND_INTEL_SST + help + This option enables support for Intel Mid Vibrator Driver. Say Y + here if you want to enable the vibrator functionality for CTP + + To compile this driver as a module, choose M here. The module will + be called intel_mid_vibra. + config INPUT_UINPUT tristate "User level driver support" help diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index eb73834..f5ccb2f 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -47,4 +47,5 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o +obj-$(CONFIG_INPUT_INTEL_MID_VIBRA) += intel_mid_vibra.o diff --git a/drivers/input/misc/intel_mid_vibra.c b/drivers/input/misc/intel_mid_vibra.c new file mode 100644 index 0000000..7e064ca --- /dev/null +++ b/drivers/input/misc/intel_mid_vibra.c @@ -0,0 +1,247 @@ +/* + * intel_mid_vibra.c - Intel vibrator driver for Clovertrail phone + * + * Copyright (C) 2011-12 Intel Corp + * Author: KP, Jeeja + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define VIBRA_ENABLE_GPIO 40 +#define PWM_ENABLE_GPIO 49 + + +struct vibra_info { + struct mutex lock; + struct device *dev; + int enabled; + void __iomem *shim; + const char *name; +}; + +/* Powers H-Bridge and enables audio clk */ +static void vibra_enable(struct vibra_info *info) +{ + pr_debug("Enable gpio\n"); + intel_sst_pwm_suspend(false); + gpio_set_value(PWM_ENABLE_GPIO, 1); + gpio_set_value(VIBRA_ENABLE_GPIO, 1); + info->enabled = true; +} + +static void vibra_disable(struct vibra_info *info) +{ + + pr_debug("Disable gpio\n"); + gpio_set_value(PWM_ENABLE_GPIO, 0); + gpio_set_value(VIBRA_ENABLE_GPIO, 0); + info->enabled = false; + intel_sst_pwm_suspend(true); +} + + +/******************************************************************************* + * SYSFS * + ******************************************************************************/ + +static ssize_t vibra_show_vibrator(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vibra_info *info = platform_get_drvdata(pdev); + + return sprintf(buf, "%d\n", info->enabled); + +} + +static ssize_t vibra_set_vibrator(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + long vibrator_enable; + int ret; + + struct platform_device *pdev = to_platform_device(dev); + struct vibra_info *info = platform_get_drvdata(pdev); + + if (strict_strtol(buf, 0, &vibrator_enable)) + return -EINVAL; + if (vibrator_enable == 0) + vibra_disable(info); + else if (vibrator_enable == 1) + vibra_enable(info); + else + return -EINVAL; + return len; +} + +static struct device_attribute vibra_attrs[] = { + __ATTR(vibrator, S_IRUGO | S_IWUSR, + vibra_show_vibrator, vibra_set_vibrator), +}; + +static int vibra_register_sysfs(struct vibra_info *info) +{ + int r, i; + + for (i = 0; i < ARRAY_SIZE(vibra_attrs); i++) { + r = device_create_file(info->dev, &vibra_attrs[i]); + if (r) + goto fail; + } + return 0; +fail: + while (i--) + device_remove_file(info->dev, &vibra_attrs[i]); + + return r; +} + +static void vibra_unregister_sysfs(struct vibra_info *info) +{ + int i; + + for (i = ARRAY_SIZE(vibra_attrs) - 1; i >= 0; i--) + device_remove_file(info->dev, &vibra_attrs[i]); +} + +/*** Module ***/ +#if CONFIG_PM +static int intel_mid_vibra_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vibra_info *info = platform_get_drvdata(pdev); + + pr_debug("intel_mid_vibra_suspend called\n"); + + if (info->enabled) + vibra_disable(info); + + return 0; +} + +static int intel_mid_vibra_resume(struct device *dev) +{ + pr_debug("intel_mid_vibra_resume called\n"); + return 0; +} + +static SIMPLE_DEV_PM_OPS(intel_mid_vibra_pm_ops, + intel_mid_vibra_suspend, intel_mid_vibra_resume); +#endif + +static int __init intel_mid_vibra_probe(struct platform_device *pdev) +{ + struct vibra_info *info; + int ret = 0; + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = &pdev->dev; + info->name = "intel_mid:vibrator"; + + mutex_init(&info->lock); + + platform_set_drvdata(pdev, info); + + if (vibra_register_sysfs(info) < 0) { + pr_err("could not register sysfs files\n"); + goto out; + } + + ret = gpio_request(VIBRA_ENABLE_GPIO, "VIBRA ENABLE"); + if (ret != 0) { + pr_err("gpio_request(%d) fails - %d\n", VIBRA_ENABLE_GPIO, ret); + goto goto_unregistesysfs; + } + + gpio_direction_output(VIBRA_ENABLE_GPIO, 0); + + ret = gpio_request(PWM_ENABLE_GPIO, "PWM ENABLE"); + + if (ret != 0) { + pr_err("gpio_request(%d) fails - %d\n", PWM_ENABLE_GPIO, ret); + goto goto_freegpio; + } + + gpio_direction_output(PWM_ENABLE_GPIO, 0); + + return ret; + +goto_freegpio: + gpio_free(VIBRA_ENABLE_GPIO); +goto_unregistesysfs: + vibra_unregister_sysfs(info); +out: + kfree(info); + return ret; +} + +static int __exit intel_mid_vibra_remove(struct platform_device *pdev) +{ + struct vibra_info *info = platform_get_drvdata(pdev); + gpio_free(VIBRA_ENABLE_GPIO); + gpio_free(PWM_ENABLE_GPIO); + vibra_unregister_sysfs(info); + kfree(info); + return 0; +} + + +static struct platform_driver intel_mid_vibra_driver = { + .driver = { + .name = "intel_mid_vibra", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &intel_mid_vibra_pm_ops, +#endif + }, + .probe = intel_mid_vibra_probe, + .remove = __devexit_p(intel_mid_vibra_remove), +}; + +static int __init intel_mid_vibra_init(void) +{ + pr_debug("intel_mid_vibra_init called\n"); + return platform_driver_register(&intel_mid_vibra_driver); +} +module_init(intel_mid_vibra_init); + +static void __exit intel_mid_vibra_exit(void) +{ + pr_debug("intel_mid_vibra_exit called\n"); + platform_driver_unregister(&intel_mid_vibra_driver); +} +module_exit(intel_mid_vibra_exit); + +MODULE_ALIAS("platform:intel_mid_vibra"); +MODULE_DESCRIPTION("Intel(R) MID Vibra driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("KP Jeeja "); diff --git a/include/sound/intel_sst.h b/include/sound/intel_sst.h index 3111289..c096d6c 100644 --- a/include/sound/intel_sst.h +++ b/include/sound/intel_sst.h @@ -152,4 +152,5 @@ int register_sst_card(struct intel_sst_card_ops *card); void unregister_sst_card(struct intel_sst_card_ops *card); int intel_sst_set_pll(unsigned int enable, enum intel_sst_pll_mode mode); int intel_sst_get_pll(void); +void intel_sst_pwm_suspend(unsigned int suspend); #endif /* __INTEL_SST_H__ */ diff --git a/sound/pci/sst/intel_sst.c b/sound/pci/sst/intel_sst.c index ce69d07..8d6a1f4 100644 --- a/sound/pci/sst/intel_sst.c +++ b/sound/pci/sst/intel_sst.c @@ -45,7 +45,7 @@ #include #include "intel_sst_fw_ipc.h" #include "intel_sst_common.h" - +#include MODULE_AUTHOR("Vinod Koul "); MODULE_AUTHOR("Harsha Priya "); @@ -60,6 +60,7 @@ MODULE_VERSION(SST_DRIVER_VERSION); #define CLV_I2S_3_FS_GPIO_PIN 13 #define CLV_I2S_3_TXD_GPIO_PIN 74 #define CLV_I2S_3_RXD_GPIO_PIN 75 +#define CLV_VIBRA_PWM_GPIO_PIN 49 struct intel_sst_drv *sst_drv_ctx; static struct mutex drv_ctx_lock; @@ -380,6 +381,9 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, lnw_gpio_set_alt(CLV_I2S_3_FS_GPIO_PIN, LNW_ALT_2); lnw_gpio_set_alt(CLV_I2S_3_TXD_GPIO_PIN, LNW_ALT_2); lnw_gpio_set_alt(CLV_I2S_3_RXD_GPIO_PIN, LNW_ALT_2); + lnw_gpio_set_alt(CLV_VIBRA_PWM_GPIO_PIN, LNW_ALT_2); + + vibra_pwm_configure(true); } sst_drv_ctx->lpe_stalled = 0; @@ -546,6 +550,18 @@ out: } EXPORT_SYMBOL(intel_sst_set_pll); +void intel_sst_pwm_suspend(unsigned int pwm_suspend) +{ + + if (pwm_suspend) { + pr_debug("SST_SND_DEVICE_SUSPEND doing rtpm_put\n"); + pm_runtime_put(&sst_drv_ctx->pci->dev); + } else { + pr_debug("SST_SND_DEVICE_RESUME_SYNC\n"); + pm_runtime_get_sync(&sst_drv_ctx->pci->dev); + } +} +EXPORT_SYMBOL(intel_sst_pwm_suspend); /* * The runtime_suspend/resume is pretty much similar to the legacy * suspend/resume with the noted exception below: The PCI core takes care of @@ -558,6 +574,41 @@ int intel_sst_get_pll(void) } EXPORT_SYMBOL(intel_sst_get_pll); +int vibra_pwm_configure(unsigned int enable) +{ + union sst_pwmctrl_reg pwmctrl; + + if (enable) { + + /*1. Enable the PWM by setting PWM enable bit to 1 */ + pwmctrl.full = readl(sst_drv_ctx->shim + SST_PWMCTRL); + pr_debug("Vibra:Read pwmctrl %x\n", pwmctrl.full); + pwmctrl.part.pwmenable = 1; + writel(pwmctrl.full, sst_drv_ctx->shim + SST_PWMCTRL); + + /*2. Read the PWM register to make sure there is no pending + update.*/ + pwmctrl.full = readl(sst_drv_ctx->shim + SST_PWMCTRL); + pr_debug("Read pwmctrl %x\n", pwmctrl.full); + + /*check pwnswupdate bit */ + if (pwmctrl.part.pwmswupdate) + return -EBUSY; + /*Base unit == 1*/ + pwmctrl.part.pwmswupdate = 0x1; + pwmctrl.part.pwmbu = MAX_BASEUNIT; + pwmctrl.part.pwmtd = MAX_TIMEDIVSOR; + writel(pwmctrl.full, sst_drv_ctx->shim + SST_PWMCTRL); + pr_debug("Read pwmctrl %x\n", pwmctrl.full); + } else { /*disable PWM block */ + /*1. setting PWM enable bit to 0 */ + pwmctrl.full = readl(sst_drv_ctx->shim + SST_PWMCTRL); + pwmctrl.part.pwmenable = 0; + writel(pwmctrl.full, sst_drv_ctx->shim + SST_PWMCTRL); + } + return 0; +} + static int intel_sst_runtime_suspend(struct device *dev) { union config_status_reg csr; @@ -580,6 +631,8 @@ static int intel_sst_runtime_suspend(struct device *dev) sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full); mutex_unlock(&sst_drv_ctx->sst_lock); intel_sst_set_pll(false, SST_PLL_AUDIO); + if (sst_drv_ctx->pci_id == SST_CLV_PCI_ID) + vibra_pwm_configure(false); return 0; } @@ -611,6 +664,9 @@ static int intel_sst_runtime_resume(struct device *dev) lnw_gpio_set_alt(CLV_I2S_3_FS_GPIO_PIN, LNW_ALT_2); lnw_gpio_set_alt(CLV_I2S_3_TXD_GPIO_PIN, LNW_ALT_2); lnw_gpio_set_alt(CLV_I2S_3_RXD_GPIO_PIN, LNW_ALT_2); + lnw_gpio_set_alt(CLV_VIBRA_PWM_GPIO_PIN, LNW_ALT_2); + + vibra_pwm_configure(true); } intel_sst_set_pll(true, SST_PLL_AUDIO); diff --git a/sound/pci/sst/intel_sst_common.h b/sound/pci/sst/intel_sst_common.h index 932961d..df4eef3 100644 --- a/sound/pci/sst/intel_sst_common.h +++ b/sound/pci/sst/intel_sst_common.h @@ -42,6 +42,8 @@ #define PCI_ID_LENGTH 4 #define SST_SUSPEND_DELAY 2000 #define FW_CONTEXT_MEM (64*1024) +#define MAX_TIMEDIVSOR 0xFF +#define MAX_BASEUNIT 0x80 enum sst_states { SST_FW_LOADED = 1, @@ -72,6 +74,7 @@ enum sst_states { #define SST_SHIM_SIZE 0X44 #define SST_CLKCTL 0x78 #define SST_CSR2 0x80 +#define SST_PWMCTRL 0x1000 #define SPI_MODE_ENABLE_BASE_ADDR 0xffae4000 #define FW_SIGNATURE_SIZE 4 @@ -142,6 +145,16 @@ union sst_pimr_reg { u32 full; }; +union sst_pwmctrl_reg { + struct { + u32 pwmtd:8; + u32 pwmbu:22; + u32 pwmswupdate:1; + u32 pwmenable:1; + } part; + u32 full; +}; + struct sst_stream_bufs { struct list_head node; @@ -545,6 +558,7 @@ void sst_clear_interrupt(void); int sst_download_fw(void); void free_stream_context(unsigned int str_id); void sst_clean_stream(struct stream_info *stream); +vibra_pwm_configure(unsigned int enable); /* * sst_fill_header - inline to fill sst header -- 2.7.4