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/arch/arm/mach-msm/proccomm-regulator.c b/arch/arm/mach-msm/proccomm-regulator.c
new file mode 100644
index 0000000..21a4f84
--- /dev/null
+++ b/arch/arm/mach-msm/proccomm-regulator.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2011-2012, 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/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <mach/proc_comm.h>
+#include "proccomm-regulator.h"
+
+#define MV_TO_UV(mv) ((mv)*1000)
+#define UV_TO_MV(uv) (((uv)+999)/1000)
+
+/*
+ * Wrappers for the msm_proc_comm() calls.
+ * Does basic impedance matching between what the proccomm interface
+ * expects and how the driver sees the world.
+ */
+
+/* Converts a proccomm error to an errno value. */
+static int _pcom_err_to_linux_errno(unsigned error)
+{
+	if (!error)		/* 0 == no error */
+		return 0;
+	else if (error & 0x1F)  /* bits 0..4 => parameter 1..5 out of range */
+		return -EDOM;
+	else if (error & 0x100) /* bit 8 => feature not supported */
+		return -ENOSYS;
+	else			/* anything else non-zero: unknown error */
+		return -EINVAL;
+}
+
+/* vreg_switch: (vreg ID, on/off) => (return code, <null>) */
+static int _vreg_switch(int vreg_id, bool enable)
+{
+	unsigned _id		= (unsigned)vreg_id;
+	unsigned _enable	= !!enable;
+
+	return msm_proc_comm(PCOM_VREG_SWITCH, &_id, &_enable);
+}
+
+/* vreg_set_level: (vreg ID, mV) => (return code, <null>) */
+static int _vreg_set_level(int vreg_id, int level_mV)
+{
+	unsigned _id		= (unsigned)vreg_id;
+	unsigned _level		= (unsigned)level_mV;
+	int	 rc;
+
+	rc = msm_proc_comm(PCOM_VREG_SET_LEVEL, &_id, &_level);
+
+	if (rc)
+		return rc;
+
+	return _pcom_err_to_linux_errno(_id);
+}
+
+/* vreg_pull_down: (pull down, vreg ID) => (<null>, <null>) */
+/* Returns error code from msm_proc_comm. */
+static int _vreg_pull_down(int vreg_id, bool pull_down)
+{
+	unsigned _id		= (unsigned)vreg_id;
+	unsigned _enable	= !!pull_down;
+
+	return msm_proc_comm(PCOM_VREG_PULLDOWN, &_enable, &_id);
+}
+
+struct proccomm_regulator_drvdata {
+	struct regulator_desc	rdesc;
+	int			rise_time;
+	int			last_voltage;
+	bool			enabled;
+	bool			negative;
+};
+
+static int proccomm_vreg_enable(struct regulator_dev *rdev)
+{
+	struct proccomm_regulator_drvdata *ddata;
+	int rc;
+
+	ddata = rdev_get_drvdata(rdev);
+	rc = _vreg_switch(rdev_get_id(rdev), VREG_SWITCH_ENABLE);
+
+	if (rc) {
+		dev_err(rdev_get_dev(rdev),
+			"could not enable regulator %d (%s): %d\n",
+			rdev_get_id(rdev), ddata->rdesc.name, rc);
+	} else {
+		dev_dbg(rdev_get_dev(rdev),
+			"enabled regulator %d (%s)\n",
+			rdev_get_id(rdev), ddata->rdesc.name);
+		ddata->enabled = 1;
+	}
+
+	return rc;
+}
+
+static int proccomm_vreg_disable(struct regulator_dev *rdev)
+{
+	struct proccomm_regulator_drvdata *ddata;
+	int rc;
+
+	ddata = rdev_get_drvdata(rdev);
+	rc = _vreg_switch(rdev_get_id(rdev), VREG_SWITCH_DISABLE);
+
+	if (rc) {
+		dev_err(rdev_get_dev(rdev),
+			"could not disable regulator %d (%s): %d\n",
+			rdev_get_id(rdev), ddata->rdesc.name, rc);
+	} else {
+		dev_dbg(rdev_get_dev(rdev),
+			"disabled regulator %d (%s)\n",
+			rdev_get_id(rdev), ddata->rdesc.name);
+		ddata->enabled = 0;
+	}
+
+	return rc;
+}
+
+static int proccomm_vreg_is_enabled(struct regulator_dev *rdev)
+{
+	struct proccomm_regulator_drvdata *ddata = rdev_get_drvdata(rdev);
+
+	return ddata->enabled;
+}
+
+static int proccomm_vreg_rise_time(struct regulator_dev *rdev)
+{
+	struct proccomm_regulator_drvdata *ddata = rdev_get_drvdata(rdev);
+
+	return ddata->rise_time;
+}
+
+static int proccomm_vreg_get_voltage(struct regulator_dev *rdev)
+{
+
+	struct proccomm_regulator_drvdata *ddata = rdev_get_drvdata(rdev);
+
+	return MV_TO_UV(ddata->last_voltage);
+}
+
+static int proccomm_vreg_set_voltage(struct regulator_dev *rdev,
+					int min_uV, int max_uV, unsigned *sel)
+{
+	struct proccomm_regulator_drvdata *ddata = rdev_get_drvdata(rdev);
+	int level_mV = UV_TO_MV(min_uV);
+	int rc;
+
+	rc = _vreg_set_level(rdev_get_id(rdev),
+			ddata->negative ? -level_mV : level_mV);
+
+	if (rc) {
+		dev_err(rdev_get_dev(rdev),
+			"could not set voltage for regulator %d (%s) "
+			"to %d mV: %d\n",
+			rdev_get_id(rdev), ddata->rdesc.name, level_mV, rc);
+	} else {
+		dev_dbg(rdev_get_dev(rdev),
+			"voltage for regulator %d (%s) set to %d mV\n",
+			rdev_get_id(rdev), ddata->rdesc.name, level_mV);
+		ddata->last_voltage = level_mV;
+	}
+
+	return rc;
+}
+
+static struct regulator_ops proccomm_regulator_ops = {
+	.enable		= proccomm_vreg_enable,
+	.disable	= proccomm_vreg_disable,
+	.is_enabled	= proccomm_vreg_is_enabled,
+	.get_voltage	= proccomm_vreg_get_voltage,
+	.set_voltage	= proccomm_vreg_set_voltage,
+	.enable_time	= proccomm_vreg_rise_time,
+};
+
+/*
+ * Create and register a struct regulator_dev based on the information in
+ * a struct proccomm_regulator_info.
+ * Fills in the rdev field in struct proccomm_regulator_info.
+ */
+static struct regulator_dev *__devinit create_proccomm_rdev(
+	struct proccomm_regulator_info *info, struct device *parent)
+{
+	const char *name;
+	struct proccomm_regulator_drvdata *d;
+	struct regulator_dev *rdev;
+	int rc = 0;
+
+	if (info->id < 0) {
+		dev_err(parent, "invalid regulator id %d\n", info->id);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	name = info->init_data.constraints.name;
+
+	if (!name) {
+		dev_err(parent,
+			"could not register regulator with id %d: "
+			"no name specified\n", info->id);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if (info->pulldown > 0) {
+		rc = _vreg_pull_down(info->id, info->pulldown);
+		if (rc) {
+			dev_err(parent,
+				"probing for regulator %d (%s) failed\n",
+				info->id, name);
+			goto out;
+		}
+	}
+
+	d = kzalloc(sizeof(*d), GFP_KERNEL);
+
+	if (!d) {
+		dev_err(parent,
+			"could not allocate struct proccomm_regulator_drvdata "
+			"for regulator %d (%s)\n", info->id, name);
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	d->rdesc.name	= name;
+	d->rdesc.id	= info->id;
+	d->rdesc.ops	= &proccomm_regulator_ops;
+	d->rdesc.type	= REGULATOR_VOLTAGE;
+	d->rdesc.owner	= THIS_MODULE;
+	d->rise_time	= info->rise_time;
+	d->enabled	= 0;
+	d->negative	= info->negative;
+	d->rdesc.n_voltages = info->n_voltages;
+
+	rdev = regulator_register(&d->rdesc, parent, &info->init_data, d, NULL);
+
+	if (IS_ERR(rdev)) {
+		rc = PTR_ERR(rdev);
+		dev_err(parent, "error registering regulator %d (%s): %d\n",
+				info->id, name, rc);
+		goto clean;
+	}
+
+	dev_dbg(parent, "registered regulator %d (%s)\n", info->id, name);
+
+	return rdev;
+
+clean:
+	kfree(d);
+out:
+	return ERR_PTR(rc);
+}
+
+/*
+ * Unregister and destroy a struct regulator_dev created by
+ * create_proccomm_rdev.
+ */
+static void destroy_proccomm_rdev(struct regulator_dev *rdev)
+{
+	struct proccomm_regulator_drvdata *d;
+
+	if (!rdev)
+		return;
+
+	d = rdev_get_drvdata(rdev);
+
+	regulator_unregister(rdev);
+
+	dev_dbg(rdev_get_dev(rdev)->parent,
+		"unregistered regulator %d (%s)\n",
+		d->rdesc.id, d->rdesc.name);
+
+	kfree(d);
+}
+
+
+static int __devinit proccomm_vreg_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct proccomm_regulator_platform_data *pdata = dev->platform_data;
+	struct regulator_dev **rdevs;
+	int rc = 0;
+	size_t i = 0;
+
+	if (!pdata) {
+		dev_err(dev, "invalid platform data\n");
+		rc = -EINVAL;
+		goto check_fail;
+	}
+
+	if (pdata->nregs == 0) {
+		dev_err(dev, "registering an empty regulator list; "
+				"this is probably not what you want\n");
+		rc = -EINVAL;
+		goto check_fail;
+	}
+
+	rdevs = kcalloc(pdata->nregs, sizeof(*rdevs), GFP_KERNEL);
+
+	if (!rdevs) {
+		dev_err(dev, "could not allocate storage for "
+				"struct regulator_dev array\n");
+		rc = -ENOMEM;
+		goto check_fail;
+	}
+
+	platform_set_drvdata(pdev, rdevs);
+
+	dev_dbg(dev, "registering %d proccomm regulators\n", pdata->nregs);
+
+	for (i = 0; i < pdata->nregs; i++) {
+		rdevs[i] = create_proccomm_rdev(&pdata->regs[i], dev);
+		if (IS_ERR(rdevs[i])) {
+			rc = PTR_ERR(rdevs[i]);
+			goto backout;
+		}
+	}
+
+	dev_dbg(dev, "%d proccomm regulators registered\n", pdata->nregs);
+
+	return rc;
+
+backout:
+	while (--i >= 0)
+		destroy_proccomm_rdev(rdevs[i]);
+
+	kfree(rdevs);
+
+check_fail:
+	return rc;
+}
+
+static int __devexit proccomm_vreg_remove(struct platform_device *pdev)
+{
+	struct proccomm_regulator_platform_data *pdata;
+	struct regulator_dev **rdevs;
+	size_t i;
+
+	pdata = pdev->dev.platform_data;
+	rdevs = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->nregs; i++)
+		destroy_proccomm_rdev(rdevs[i]);
+
+	kfree(rdevs);
+
+	return 0;
+}
+
+static struct platform_driver proccomm_vreg_driver = {
+	.probe	= proccomm_vreg_probe,
+	.remove = __devexit_p(proccomm_vreg_remove),
+	.driver = {
+		.name	= PROCCOMM_REGULATOR_DEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init proccomm_vreg_init(void)
+{
+	return platform_driver_register(&proccomm_vreg_driver);
+}
+postcore_initcall(proccomm_vreg_init);
+
+static void __exit proccomm_vreg_exit(void)
+{
+	platform_driver_unregister(&proccomm_vreg_driver);
+}
+module_exit(proccomm_vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ProcComm regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" PROCCOMM_REGULATOR_DEV_NAME);