Merge commit 'AU_LINUX_ANDROID_ICS.04.00.04.00.126' into msm-3.4
AU_LINUX_ANDROID_ICS.04.00.04.00.126 from msm-3.0.
First parent is from google/android-3.4.
* commit 'AU_LINUX_ANDROID_ICS.04.00.04.00.126': (8712 commits)
PRNG: Device tree entry for qrng device.
vidc:1080p: Set video core timeout value for Thumbnail mode
msm: sps: improve the debugging support in SPS driver
board-8064 msm: Overlap secure and non secure video firmware heaps.
msm: clock: Add handoff ops for 7x30 and copper XO clocks
msm_fb: display: Wait for external vsync before DTV IOMMU unmap
msm: Fix ciruclar dependency in debug UART settings
msm: gdsc: Add GDSC regulator driver for msm-copper
defconfig: Enable Mobicore Driver.
mobicore: Add mobicore driver.
mobicore: rename variable to lower case.
mobicore: rename folder.
mobicore: add makefiles
mobicore: initial import of kernel driver
ASoC: msm: Add SLIMBUS_2_RX CPU DAI
board-8064-gpio: Update FUNC for EPM SPI CS
msm_fb: display: Remove chicken bit config during video playback
mmc: msm_sdcc: enable the sanitize capability
msm-fb: display: lm2 writeback support on mpq platfroms
msm_fb: display: Disable LVDS phy & pll during panel off
...
Signed-off-by: Steve Muckle <smuckle@codeaurora.org>
diff --git a/drivers/leds/leds-msm-pdm.c b/drivers/leds/leds-msm-pdm.c
new file mode 100644
index 0000000..467026b
--- /dev/null
+++ b/drivers/leds/leds-msm-pdm.c
@@ -0,0 +1,234 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+
+/* Early-suspend level */
+#define LED_SUSPEND_LEVEL 1
+#endif
+
+#define PDM_DUTY_MAXVAL BIT(16)
+#define PDM_DUTY_REFVAL BIT(15)
+
+struct pdm_led_data {
+ struct led_classdev cdev;
+ void __iomem *perph_base;
+ int pdm_offset;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+};
+
+static void msm_led_brightness_set_percent(struct pdm_led_data *led,
+ int duty_per)
+{
+ u16 duty_val;
+
+ duty_val = PDM_DUTY_REFVAL - ((PDM_DUTY_MAXVAL * duty_per) / 100);
+
+ if (!duty_per)
+ duty_val--;
+
+ writel_relaxed(duty_val, led->perph_base + led->pdm_offset);
+}
+
+static void msm_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct pdm_led_data *led =
+ container_of(led_cdev, struct pdm_led_data, cdev);
+
+ msm_led_brightness_set_percent(led, (value * 100) / LED_FULL);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_led_pdm_suspend(struct device *dev)
+{
+ struct pdm_led_data *led = dev_get_drvdata(dev);
+
+ msm_led_brightness_set_percent(led, 0);
+
+ return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void msm_led_pdm_early_suspend(struct early_suspend *h)
+{
+ struct pdm_led_data *led = container_of(h,
+ struct pdm_led_data, early_suspend);
+
+ msm_led_pdm_suspend(led->cdev.dev->parent);
+}
+
+#endif
+
+static const struct dev_pm_ops msm_led_pdm_pm_ops = {
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = msm_led_pdm_suspend,
+#endif
+};
+#endif
+
+static int __devinit msm_pdm_led_probe(struct platform_device *pdev)
+{
+ const struct led_info *pdata = pdev->dev.platform_data;
+ struct pdm_led_data *led;
+ struct resource *res, *ioregion;
+ u32 tcxo_pdm_ctl;
+ int rc;
+
+ if (!pdata) {
+ pr_err("platform data is invalid\n");
+ return -EINVAL;
+ }
+
+ if (pdev->id > 2) {
+ pr_err("pdm id is invalid\n");
+ return -EINVAL;
+ }
+
+ led = kzalloc(sizeof(struct pdm_led_data), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ /* Enable runtime PM ops, start in ACTIVE mode */
+ rc = pm_runtime_set_active(&pdev->dev);
+ if (rc < 0)
+ dev_dbg(&pdev->dev, "unable to set runtime pm state\n");
+ pm_runtime_enable(&pdev->dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ pr_err("get resource failed\n");
+ rc = -EINVAL;
+ goto err_get_res;
+ }
+
+ ioregion = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+ if (!ioregion) {
+ pr_err("request for mem region failed\n");
+ rc = -ENOMEM;
+ goto err_get_res;
+ }
+
+ led->perph_base = ioremap(res->start, resource_size(res));
+ if (!led->perph_base) {
+ pr_err("ioremap failed\n");
+ rc = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ /* Pulse Density Modulation(PDM) ids start with 0 and
+ * every PDM register takes 4 bytes
+ */
+ led->pdm_offset = ((pdev->id) + 1) * 4;
+
+ /* program tcxo_pdm_ctl register to enable pdm*/
+ tcxo_pdm_ctl = readl_relaxed(led->perph_base);
+ tcxo_pdm_ctl |= (1 << pdev->id);
+ writel_relaxed(tcxo_pdm_ctl, led->perph_base);
+
+ /* Start with LED in off state */
+ msm_led_brightness_set_percent(led, 0);
+
+ led->cdev.brightness_set = msm_led_brightness_set;
+ led->cdev.name = pdata->name ? : "leds-msm-pdm";
+
+ rc = led_classdev_register(&pdev->dev, &led->cdev);
+ if (rc) {
+ pr_err("led class registration failed\n");
+ goto err_led_reg;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ led->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
+ LED_SUSPEND_LEVEL;
+ led->early_suspend.suspend = msm_led_pdm_early_suspend;
+ register_early_suspend(&led->early_suspend);
+#endif
+
+ platform_set_drvdata(pdev, led);
+ return 0;
+
+err_led_reg:
+ iounmap(led->perph_base);
+err_ioremap:
+ release_mem_region(res->start, resource_size(res));
+err_get_res:
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ kfree(led);
+ return rc;
+}
+
+static int __devexit msm_pdm_led_remove(struct platform_device *pdev)
+{
+ struct pdm_led_data *led = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&led->early_suspend);
+#endif
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ led_classdev_unregister(&led->cdev);
+ msm_led_brightness_set_percent(led, 0);
+ iounmap(led->perph_base);
+ release_mem_region(res->start, resource_size(res));
+ kfree(led);
+
+ return 0;
+}
+
+static struct platform_driver msm_pdm_led_driver = {
+ .probe = msm_pdm_led_probe,
+ .remove = __devexit_p(msm_pdm_led_remove),
+ .driver = {
+ .name = "leds-msm-pdm",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM_SLEEP
+ .pm = &msm_led_pdm_pm_ops,
+#endif
+ },
+};
+
+static int __init msm_pdm_led_init(void)
+{
+ return platform_driver_register(&msm_pdm_led_driver);
+}
+module_init(msm_pdm_led_init);
+
+static void __exit msm_pdm_led_exit(void)
+{
+ platform_driver_unregister(&msm_pdm_led_driver);
+}
+module_exit(msm_pdm_led_exit);
+
+MODULE_DESCRIPTION("MSM PDM LEDs driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:leds-msm-pdm");