--- v4
+++ v5
@@ -15,25 +15,30 @@
Changes in v4:
No changes
- drivers/mfd/Kconfig | 9 ++
+Changes in v5:
+ Make use of devm_xxx and regmap MMIO API's.
+
+ drivers/mfd/Kconfig | 11 ++
drivers/mfd/Makefile | 1 +
- drivers/mfd/ti_am335x_tscadc.c | 193 ++++++++++++++++++++++++++++++++++
- include/linux/mfd/ti_am335x_tscadc.h | 133 +++++++++++++++++++++++
- 4 files changed, 336 insertions(+), 0 deletions(-)
+ drivers/mfd/ti_am335x_tscadc.c | 250 ++++++++++++++++++++++++++++++++++
+ include/linux/mfd/ti_am335x_tscadc.h | 137 +++++++++++++++++++
+ 4 files changed, 399 insertions(+), 0 deletions(-)
create mode 100644 drivers/mfd/ti_am335x_tscadc.c
create mode 100644 include/linux/mfd/ti_am335x_tscadc.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
-index b1a1462..e472184 100644
+index b1a1462..8a1d655 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
-@@ -94,6 +94,15 @@ config MFD_TI_SSP
+@@ -94,6 +94,17 @@ config MFD_TI_SSP
To compile this driver as a module, choose M here: the
module will be called ti-ssp.
+config MFD_TI_AM335X_TSCADC
+ tristate "TI ADC / Touch Screen chip support"
-+ depends on ARCH_OMAP2PLUS
++ select MFD_CORE
++ select REGMAP
++ select REGMAP_MMIO
+ help
+ If you say yes here you get support for Texas Instruments series
+ of Touch Screen /ADC chips.
@@ -57,10 +62,10 @@
obj-$(CONFIG_MFD_STMPE) += stmpe.o
diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c
new file mode 100644
-index 0000000..ae93b48
+index 0000000..14df67b
--- /dev/null
+++ b/drivers/mfd/ti_am335x_tscadc.c
-@@ -0,0 +1,193 @@
+@@ -0,0 +1,250 @@
+/*
+ * TI Touch Screen / ADC MFD driver
+ *
@@ -82,20 +87,32 @@
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
++#include <linux/regmap.h>
+#include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
++
+#include <linux/mfd/ti_am335x_tscadc.h>
+
+static unsigned int tscadc_readl(struct ti_tscadc_dev *tsadc, unsigned int reg)
+{
-+ return readl(tsadc->tscadc_base + reg);
++ unsigned int val;
++
++ regmap_read(tsadc->regmap_tscadc, reg, &val);
++ return val;
+}
+
+static void tscadc_writel(struct ti_tscadc_dev *tsadc, unsigned int reg,
+ unsigned int val)
+{
-+ writel(val, tsadc->tscadc_base + reg);
-+}
++ regmap_write(tsadc->regmap_tscadc, reg, val);
++}
++
++static const struct regmap_config tscadc_regmap_config = {
++ .name = "ti_tscadc",
++ .reg_bits = 32,
++ .reg_stride = 4,
++ .val_bits = 32,
++};
+
+static void tscadc_idle_config(struct ti_tscadc_dev *config)
+{
@@ -135,7 +152,8 @@
+ }
+
+ /* Allocate memory for device */
-+ tscadc = kzalloc(sizeof(struct ti_tscadc_dev), GFP_KERNEL);
++ tscadc = devm_kzalloc(&pdev->dev,
++ sizeof(struct ti_tscadc_dev), GFP_KERNEL);
+ if (!tscadc) {
+ dev_err(&pdev->dev, "failed to allocate memory.\n");
+ return -ENOMEM;
@@ -143,18 +161,28 @@
+ tscadc->dev = &pdev->dev;
+ tscadc->irq = irq;
+
-+ res = request_mem_region(res->start, resource_size(res), pdev->name);
++ res = devm_request_mem_region(&pdev->dev,
++ res->start, resource_size(res), pdev->name);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to reserve registers.\n");
+ err = -EBUSY;
-+ goto err_free_mem;
-+ }
-+
-+ tscadc->tscadc_base = ioremap(res->start, resource_size(res));
++ goto err;
++ }
++
++ tscadc->tscadc_base = devm_ioremap(&pdev->dev,
++ res->start, resource_size(res));
+ if (!tscadc->tscadc_base) {
+ dev_err(&pdev->dev, "failed to map registers.\n");
+ err = -ENOMEM;
-+ goto err_release_mem_region;
++ goto err;
++ }
++
++ tscadc->regmap_tscadc = devm_regmap_init_mmio(&pdev->dev,
++ tscadc->tscadc_base, &tscadc_regmap_config);
++ if (IS_ERR(tscadc->regmap_tscadc)) {
++ dev_err(&pdev->dev, "regmap init failed\n");
++ err = PTR_ERR(tscadc->regmap_tscadc);
++ goto err;
+ }
+
+ pm_runtime_enable(&pdev->dev);
@@ -206,43 +234,77 @@
+ if (err < 0)
+ goto err_disable_clk;
+
++ device_init_wakeup(&pdev->dev, true);
+ platform_set_drvdata(pdev, tscadc);
++
+ return 0;
+
+err_disable_clk:
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
-+ iounmap(tscadc->tscadc_base);
-+err_release_mem_region:
-+ release_mem_region(res->start, resource_size(res));
-+ mfd_remove_devices(tscadc->dev);
-+err_free_mem:
-+ kfree(tscadc);
++err:
+ return err;
+}
+
+static int __devexit ti_tscadc_remove(struct platform_device *pdev)
+{
+ struct ti_tscadc_dev *tscadc = platform_get_drvdata(pdev);
-+ struct resource *res;
+
+ tscadc_writel(tscadc, REG_SE, 0x00);
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ iounmap(tscadc->tscadc_base);
-+ release_mem_region(res->start, resource_size(res));
+
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ mfd_remove_devices(tscadc->dev);
-+ kfree(tscadc);
++
+ return 0;
+}
++
++#ifdef CONFIG_PM
++static int tscadc_suspend(struct device *dev)
++{
++ struct ti_tscadc_dev *tscadc_dev = dev_get_drvdata(dev);
++
++ tscadc_writel(tscadc_dev, REG_SE, 0x00);
++ pm_runtime_put_sync(dev);
++
++ return 0;
++}
++
++static int tscadc_resume(struct device *dev)
++{
++ struct ti_tscadc_dev *tscadc_dev = dev_get_drvdata(dev);
++ unsigned int restore, ctrl;
++
++ pm_runtime_get_sync(dev);
++
++ /* context restore */
++ ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_TSCENB |
++ CNTRLREG_STEPID | CNTRLREG_4WIRE;
++ tscadc_writel(tscadc_dev, REG_CTRL, ctrl);
++ tscadc_idle_config(tscadc_dev);
++ tscadc_writel(tscadc_dev, REG_SE, STPENB_STEPENB);
++ restore = tscadc_readl(tscadc_dev, REG_CTRL);
++ tscadc_writel(tscadc_dev, REG_CTRL,
++ (restore | CNTRLREG_TSCSSENB));
++
++ return 0;
++}
++
++static const struct dev_pm_ops tscadc_pm_ops = {
++ .suspend = tscadc_suspend,
++ .resume = tscadc_resume,
++};
++#define TSCADC_PM_OPS (&tscadc_pm_ops)
++#else
++#define TSCADC_PM_OPS NULL
++#endif
+
+static struct platform_driver ti_tscadc_driver = {
+ .driver = {
+ .name = "ti_tscadc",
+ .owner = THIS_MODULE,
++ .pm = TSCADC_PM_OPS,
+ },
+ .probe = ti_tscadc_probe,
+ .remove = __devexit_p(ti_tscadc_remove),
@@ -256,10 +318,10 @@
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h
new file mode 100644
-index 0000000..b1eec17
+index 0000000..b7232b1
--- /dev/null
+++ b/include/linux/mfd/ti_am335x_tscadc.h
-@@ -0,0 +1,133 @@
+@@ -0,0 +1,137 @@
+#ifndef __LINUX_TI_AM335X_TSCADC_MFD_H
+#define __LINUX_TI_AM335X_TSCADC_MFD_H
+
@@ -302,6 +364,9 @@
+#define REG_FIFO1 0x200
+
+/* Register Bitfields */
++/* IRQ wakeup enable */
++#define IRQWKUP_ENB BIT(0)
++
+/* Step Enable */
+#define STEPENB_MASK (0x1FFFF << 0)
+#define STEPENB(val) ((val) << 0)
@@ -387,6 +452,7 @@
+
+struct ti_tscadc_dev {
+ struct device *dev;
++ struct regmap *regmap_tscadc;
+ void __iomem *tscadc_base;
+ int irq;
+ struct mfd_cell cells[TSCADC_CELLS];