lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 7 Aug 2012 16:09:30 +0300
From:	Ferruh Yigit <fery@...ress.com>
To:	Dmitry Torokhov <dmitry.torokhov@...il.com>
CC:	Kevin McNeely <kev@...ress.com>, Ferruh YIGIT <fery@...ress.com>,
	Javier Martinez Canillas <javier@...hile0.org>,
	Henrik Rydberg <rydberg@...omail.se>,
	Shawn Landden <shawnlandden@...il.com>,
	Ashish Jangam <ashish.jangam@...tcummins.com>,
	Olivier Sobrie <olivier@...rie.be>,
	linux-input@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH 1/4] Input: cyttsp4 - bus driver for Cypress TMA4XX touchscreen devices

From: Ferruh YIGIT <fery@...ress.com>

This driver is for Cypress TrueTouch(tm) Standard Product controllers,
Generation4 devices.

Driver consist of four main modules:

Bus driver: Linux bus driver implementation, binds other modules.
Core driver: Core module that communicate with TTSP controller.
MT driver: MultiTouch driver, converts touch information to host specific
touch events
Adapter driver: Communication adapter between host and controller, like
I2C or SPI.

This is Cyttsp4 TTSP Bus Driver,
Provides binding between Adapter, Core, and TTSP Modules.

A complete set of corresponding Adapter, Core, and TTSP module
devices and drivers must be registered with the TTSP Bus handler

Signed-off-by: Ferruh YIGIT <fery@...ress.com>
---
 drivers/input/touchscreen/Kconfig       |    9 +
 drivers/input/touchscreen/Makefile      |    1 +
 drivers/input/touchscreen/cyttsp4_bus.c |  608 +++++++++++++++++++++++++++++++
 include/linux/cyttsp4_bus.h             |  271 ++++++++++++++
 4 files changed, 889 insertions(+)
 create mode 100644 drivers/input/touchscreen/cyttsp4_bus.c
 create mode 100644 include/linux/cyttsp4_bus.h

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 1ba232c..4a65736 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -179,6 +179,15 @@ config TOUCHSCREEN_CYTTSP_SPI
          To compile this driver as a module, choose M here: the
          module will be called cyttsp_spi.

+config CYPRESS_CYTTSP4_BUS
+       bool "Cypress TTSP core bus"
+       default n
+       help
+         This option enables support Cypress TTSP core bus.
+         This support is needed for various device and drivers
+         using Cypress TrueTouch(TM) Standard Product
+         protocol.
+
 config TOUCHSCREEN_DA9034
        tristate "Touchscreen support for Dialog Semiconductor DA9034"
        depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 178eb12..ab84aec 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -73,3 +73,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)    += mainstone-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)      += zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)      += w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)     += tps6507x-ts.o
+obj-$(CONFIG_CYPRESS_CYTTSP4_BUS) += cyttsp4_bus.o
diff --git a/drivers/input/touchscreen/cyttsp4_bus.c b/drivers/input/touchscreen/cyttsp4_bus.c
new file mode 100644
index 0000000..2e97088
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp4_bus.c
@@ -0,0 +1,608 @@
+/*
+ * cyttsp4_bus.c
+ * Cypress TrueTouch(TM) Standard Product V4 Bus Driver.
+ * For use with Cypress Txx4xx parts.
+ * Supported parts include:
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2012 Cypress Semiconductor
+ * Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
+ *
+ * Author: Aleksej Makarov aleksej.makarov@...yericsson.com
+ * Modified by: Cypress Semiconductor for complete set of TTSP Bus interfaces.
+ *
+ * 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.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@...ress.com>
+ *
+ */
+
+#include <linux/cyttsp4_bus.h>
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/limits.h>
+
+static DEFINE_MUTEX(core_lock);
+static LIST_HEAD(adapter_list);
+static LIST_HEAD(core_dev_list);
+static LIST_HEAD(cyttsp4_dev_list);
+
+struct bus_type cyttsp4_bus_type;
+
+static void cyttsp4_dev_release(struct device *dev)
+{
+       dev_vdbg(dev, "%s: Enter\n", __func__);
+       put_device(dev->parent);
+}
+
+static struct device_type cyttsp4_dev_type = {
+       .release = cyttsp4_dev_release
+};
+
+static struct device_type cyttsp4_core_type = {
+       .release = cyttsp4_dev_release
+};
+
+static int _cyttsp4_register_dev(struct cyttsp4_device *pdev,
+               struct cyttsp4_core *core)
+{
+       int ret;
+
+       if (!pdev->dev.parent)
+               pdev->dev.parent = get_device(&core->dev);
+       /* Assign (new) core */
+       pdev->core = core;
+       /* Check whether this device is registered before */
+       if (pdev->dev.bus == &cyttsp4_bus_type &&
+                       pdev->dev.type == &cyttsp4_dev_type)
+               return 0;
+
+       pdev->dev.bus = &cyttsp4_bus_type;
+       pdev->dev.type = &cyttsp4_dev_type;
+       dev_set_name(&pdev->dev, "%s.%s", pdev->name,  core->id);
+
+       ret = device_register(&pdev->dev);
+       dev_dbg(&pdev->dev,
+               "%s: Registering device '%s'. Parent at '%s', err = %d\n",
+                __func__, dev_name(&pdev->dev),
+                dev_name(pdev->dev.parent), ret);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to register device, err %d\n",
+                       __func__, ret);
+               pdev->dev.bus = NULL;
+               pdev->dev.type = NULL;
+               pdev->core = NULL;
+       }
+       return ret;
+}
+
+static int _cyttsp4_register_core(struct cyttsp4_core *pdev,
+               struct cyttsp4_adapter *adap)
+{
+       int ret;
+
+       if (!pdev->dev.parent)
+               pdev->dev.parent = get_device(adap->dev);
+       /* Assign (new) adapter */
+       pdev->adap = adap;
+       /* Check whether this core is registered before */
+       if (pdev->dev.bus == &cyttsp4_bus_type &&
+                       pdev->dev.type == &cyttsp4_core_type)
+               return 0;
+
+       pdev->dev.bus = &cyttsp4_bus_type;
+       pdev->dev.type = &cyttsp4_core_type;
+       dev_set_name(&pdev->dev, "%s.%s", pdev->id,  adap->id);
+
+       ret = device_register(&pdev->dev);
+       dev_dbg(&pdev->dev,
+               "%s: Registering device '%s'. Parent at '%s', err = %d\n",
+                __func__, dev_name(&pdev->dev),
+                dev_name(pdev->dev.parent), ret);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to register device, err %d\n",
+                       __func__, ret);
+               pdev->dev.bus = NULL;
+               pdev->dev.type = NULL;
+               pdev->adap = NULL;
+       }
+       return ret;
+}
+
+static struct cyttsp4_adapter *find_adapter(char const *adap_id)
+{
+       struct cyttsp4_adapter *a;
+
+       list_for_each_entry(a, &adapter_list, node)
+               if (!strncmp(a->id, adap_id, NAME_MAX))
+                       return a;
+       return NULL;
+}
+
+static struct cyttsp4_core *find_core(char const *core_id)
+{
+       struct cyttsp4_core *d;
+
+       list_for_each_entry(d, &core_dev_list, node)
+               if (!strncmp(d->id, core_id, NAME_MAX) && d->dev.driver)
+                       return d;
+       return NULL;
+}
+
+static void rescan_devices(struct cyttsp4_core *core)
+{
+       struct cyttsp4_device *d;
+
+       list_for_each_entry(d, &cyttsp4_dev_list, node)
+               if (!d->core && !strncmp(core->id, d->core_id, NAME_MAX))
+                       _cyttsp4_register_dev(d, core);
+}
+
+static void rescan_cores(struct cyttsp4_adapter *adap)
+{
+       struct cyttsp4_core *d;
+
+       list_for_each_entry(d, &core_dev_list, node)
+               if (!d->adap && !strncmp(adap->id, d->adap_id, NAME_MAX))
+                       _cyttsp4_register_core(d, adap);
+}
+
+int cyttsp4_register_device(struct cyttsp4_device *pdev)
+{
+       int ret = 0;
+       struct cyttsp4_core *core;
+
+       if (!pdev)
+               return -EINVAL;
+       mutex_lock(&core_lock);
+       list_add(&pdev->node, &cyttsp4_dev_list);
+       pr_debug("%s: '%s' added to cyttsp4_dev_list\n", __func__, pdev->name);
+       core = find_core(pdev->core_id);
+       if (core)
+               ret = _cyttsp4_register_dev(pdev, core);
+       mutex_unlock(&core_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cyttsp4_register_device);
+
+static int cyttsp4_match_dev(struct device *dev, void *data)
+{
+       return dev == (struct device *)data;
+}
+
+void cyttsp4_unregister_device(struct cyttsp4_device *pdev)
+{
+       if (!pdev)
+               return;
+       mutex_lock(&core_lock);
+       if (bus_find_device(&cyttsp4_bus_type, NULL, &pdev->dev,
+                       cyttsp4_match_dev)) {
+               dev_dbg(&pdev->dev, "%s: Unregistering device '%s'.\n",
+                       __func__, dev_name(&pdev->dev));
+               /* Put reference taken by bus_find_device() */
+               put_device(&pdev->dev);
+               device_unregister(&pdev->dev);
+       }
+       list_del(&pdev->node);
+       pr_debug("%s: '%s' removed from cyttsp4_dev_list\n", __func__,
+               pdev->name);
+       mutex_unlock(&core_lock);
+}
+EXPORT_SYMBOL_GPL(cyttsp4_unregister_device);
+
+int cyttsp4_register_core_device(struct cyttsp4_core *pdev)
+{
+       int ret = 0;
+       struct cyttsp4_adapter *adap;
+
+       if (!pdev)
+               return -EINVAL;
+       mutex_lock(&core_lock);
+       if (find_core(pdev->id)) {
+               pr_debug("%s: core id '%s' already exists\n",
+                               __func__, pdev->id);
+               ret = -EINVAL;
+               goto fail;
+       }
+       list_add(&pdev->node, &core_dev_list);
+       pr_debug("%s: '%s' added to core_dev_list\n", __func__, pdev->name);
+       adap = find_adapter(pdev->adap_id);
+       if (adap) {
+               pr_debug("%s: adapter for '%s' is '%s'\n", __func__,
+                               pdev->id, dev_name(adap->dev));
+               ret = _cyttsp4_register_core(pdev, adap);
+               if (!ret)
+                       rescan_devices(pdev);
+       }
+fail:
+       mutex_unlock(&core_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cyttsp4_register_core_device);
+
+int cyttsp4_add_adapter(char const *id, struct cyttsp4_ops const *ops,
+               struct device *parent)
+{
+       int rc = 0;
+       struct cyttsp4_adapter *a;
+
+       if (!parent) {
+               dev_err(parent, "%s: need parent for '%s'\n", __func__, id);
+               return -EINVAL;
+       }
+       mutex_lock(&core_lock);
+       if (find_adapter(id)) {
+               dev_err(parent, "%s: adapter '%s' already exists\n",
+                               __func__, id);
+               rc = -EINVAL;
+               goto fail;
+       }
+       a = kzalloc(sizeof(*a), GFP_KERNEL);
+       if (!a) {
+               dev_err(parent, "%s: failed to allocate adapter '%s'\n",
+                               __func__, id);
+               rc = -ENOMEM;
+               goto fail;
+       }
+       memcpy(a->id, id, sizeof(a->id));
+       a->id[sizeof(a->id) - 1] = 0;
+       a->read = ops->read;
+       a->write = ops->write;
+       a->dev = parent;
+       list_add(&a->node, &adapter_list);
+       dev_dbg(parent, "%s: '%s' added to adapter_list\n", __func__, id);
+       rescan_cores(a);
+fail:
+       mutex_unlock(&core_lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(cyttsp4_add_adapter);
+
+int cyttsp4_del_adapter(char const *id)
+{
+       int rc = 0;
+       struct cyttsp4_adapter *adap;
+       struct cyttsp4_core *core_dev;
+
+       mutex_lock(&core_lock);
+       adap = find_adapter(id);
+       if (!adap) {
+               pr_err("%s: adapter '%s' does not exist\n",
+                       __func__, id);
+               rc = -EINVAL;
+               goto fail;
+       }
+
+       list_for_each_entry(core_dev, &core_dev_list, node)
+               if (core_dev->adap == adap)
+                       core_dev->adap = NULL;
+
+       list_del(&adap->node);
+       kfree(adap);
+       pr_debug("%s: '%s' removed from adapter_list\n", __func__, id);
+fail:
+       mutex_unlock(&core_lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(cyttsp4_del_adapter);
+
+static struct cyttsp4_device *verify_device_type(struct device *dev)
+{
+       return dev->type == &cyttsp4_dev_type ? to_cyttsp4_device(dev) : NULL;
+}
+
+static struct cyttsp4_core *verify_core_type(struct device *dev)
+{
+       return dev->type == &cyttsp4_core_type ? to_cyttsp4_core(dev) : NULL;
+}
+
+static int cyttsp4_match_device(struct cyttsp4_device *dev, const char *name)
+{
+       return strncmp(dev->name, name, NAME_MAX) == 0;
+}
+
+static int cyttsp4_match_core_device(struct cyttsp4_core *core,
+               const char *name)
+{
+       return strncmp(core->name, name, NAME_MAX) == 0;
+}
+
+static int cyttsp4_device_match(struct device *dev, struct device_driver *drv)
+{
+       struct cyttsp4_device *cyttsp4_dev = verify_device_type(dev);
+       struct cyttsp4_core *cyttsp4_core;
+       int match;
+
+       if (cyttsp4_dev) {
+               match = cyttsp4_match_device(cyttsp4_dev, drv->name);
+               goto exit;
+       }
+       cyttsp4_core = verify_core_type(dev);
+       if (cyttsp4_core) {
+               match = cyttsp4_match_core_device(cyttsp4_core, drv->name);
+               goto exit;
+       }
+       match = 0;
+exit:
+       dev_dbg(dev, "%s: %s matching '%s' driver\n", __func__,
+                       match ? "is" : "isn't", drv->name);
+       return match;
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+                            char *buf)
+{
+       struct cyttsp4_device *cyttsp4_dev = verify_device_type(dev);
+       struct cyttsp4_core *cyttsp4_core;
+
+       char const *name;
+       int len;
+
+       if (cyttsp4_dev) {
+               name = cyttsp4_dev->name;
+               goto exit;
+       }
+       cyttsp4_core = verify_core_type(dev);
+       if (cyttsp4_core) {
+               name = cyttsp4_core->id;
+               goto exit;
+       }
+       name = "none";
+exit:
+       len = snprintf(buf, PAGE_SIZE, "ttsp4:%s\n", name);
+       return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute cyttsp4_dev_attrs[] = {
+       __ATTR_RO(modalias),
+       __ATTR_NULL,
+};
+
+#ifdef CONFIG_SUSPEND
+static int cyttsp4_pm_suspend(struct device *dev)
+{
+       struct device_driver *drv = dev->driver;
+
+       dev_dbg(dev, "%s\n", __func__);
+       if (drv && drv->pm && drv->pm->suspend)
+               return drv->pm->suspend(dev);
+       return 0;
+}
+
+static int cyttsp4_pm_resume(struct device *dev)
+{
+       struct device_driver *drv = dev->driver;
+
+       dev_dbg(dev, "%s\n", __func__);
+       if (drv && drv->pm && drv->pm->resume)
+               return drv->pm->suspend(dev);
+       return 0;
+}
+#else /* !CONFIG_SUSPEND */
+#define cyttsp4_pm_suspend             NULL
+#define cyttsp4_pm_resume              NULL
+#endif /* !CONFIG_SUSPEND */
+
+#ifdef CONFIG_PM_RUNTIME
+#define cyttsp4_pm_rt_suspend          pm_generic_runtime_suspend
+#define cyytsp4_pm_rt_resume           pm_generic_runtime_resume
+#define cyytsp4_pm_rt_idle             pm_generic_runtime_idle
+#else /* !CONFIG_PM_RUNTIME */
+#define cyttsp4_pm_rt_suspend          NULL
+#define cyytsp4_pm_rt_resume           NULL
+#define cyytsp4_pm_rt_idle             NULL
+#endif /* !CONFIG_PM_RUNTIME */
+
+static const struct dev_pm_ops cyttsp4_dev_pm_ops = {
+       .suspend = cyttsp4_pm_suspend,
+       .resume = cyttsp4_pm_resume,
+       .runtime_suspend = cyttsp4_pm_rt_suspend,
+       .runtime_resume = cyytsp4_pm_rt_resume,
+       .runtime_idle = cyytsp4_pm_rt_idle,
+};
+
+struct bus_type cyttsp4_bus_type = {
+       .name           = "ttsp4",
+       .dev_attrs      = cyttsp4_dev_attrs,
+       .match          = cyttsp4_device_match,
+       .uevent         = NULL,
+       .pm             = &cyttsp4_dev_pm_ops,
+};
+EXPORT_SYMBOL_GPL(cyttsp4_bus_type);
+
+static int cyttsp4_drv_remove(struct device *_dev)
+{
+       struct cyttsp4_driver *drv = to_cyttsp4_driver(_dev->driver);
+       struct cyttsp4_device *dev = to_cyttsp4_device(_dev);
+       return drv->remove(dev);
+}
+
+static int cyttsp4_core_drv_remove(struct device *_dev)
+{
+       struct cyttsp4_core_driver *drv = to_cyttsp4_core_driver(_dev->driver);
+       struct cyttsp4_core *dev = to_cyttsp4_core(_dev);
+       return drv->remove(dev);
+}
+
+static int cyttsp4_drv_probe(struct device *_dev)
+{
+       int rc = -ENODEV;
+       struct cyttsp4_driver *drv = to_cyttsp4_driver(_dev->driver);
+       struct cyttsp4_device *dev = to_cyttsp4_device(_dev);
+
+       rc = drv->probe(dev);
+       dev_dbg(_dev, "%s: for %s = %d\n", __func__, dev->name, rc);
+       return rc;
+}
+
+static int cyttsp4_core_drv_probe(struct device *_dev)
+{
+       int rc = -ENODEV;
+       struct cyttsp4_core_driver *drv = to_cyttsp4_core_driver(_dev->driver);
+       struct cyttsp4_core *dev = to_cyttsp4_core(_dev);
+
+       rc = drv->probe(dev);
+       dev_dbg(_dev, "%s: for %s = %d\n", __func__, dev->name, rc);
+       if (!rc)
+               rescan_devices(dev);
+       return rc;
+}
+
+int cyttsp4_register_driver(struct cyttsp4_driver *drv)
+{
+       int ret = 0;
+
+#ifdef CONFIG_MODULES
+       struct cyttsp4_device *d;
+
+       /*
+        * We need to ensure that the driver of this device's
+        * core device should exist (dependency)
+        * To do so, we traverse through the device, its core
+        * device and the driver of its core device, which requires
+        * the device itself should be registered with the system
+        */
+       mutex_lock(&core_lock);
+       list_for_each_entry(d, &cyttsp4_dev_list, node) {
+               if (!cyttsp4_match_device(d, drv->driver.name))
+                       continue;
+               if (d->core) {
+                       if (d->core->dev.driver)
+                               ret = ref_module(drv->driver.owner,
+                                       d->core->dev.driver->owner);
+                       else
+                               /* Core device exists but not core driver */
+                               ret = -ENODEV;
+               }
+               break;
+       }
+       mutex_unlock(&core_lock);
+
+       if (ret) {
+               if (ret == -ENODEV)
+                       pr_err("%s: Core driver module does not exist\n",
+                               __func__);
+               else
+                       pr_err("%s: Error getting ref to core driver module\n",
+                               __func__);
+               goto fail;
+       }
+#endif
+
+       drv->driver.bus = &cyttsp4_bus_type;
+       if (drv->probe)
+               drv->driver.probe = cyttsp4_drv_probe;
+       if (drv->remove)
+               drv->driver.remove = cyttsp4_drv_remove;
+       ret = driver_register(&drv->driver);
+fail:
+       pr_debug("%s: '%s' returned %d\n", __func__, drv->driver.name, ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cyttsp4_register_driver);
+
+int cyttsp4_register_core_driver(struct cyttsp4_core_driver *drv)
+{
+       int ret = 0;
+
+#ifdef CONFIG_MODULES
+       struct cyttsp4_core *d;
+
+       /*
+        * We need to ensure that the driver of this core device's
+        * adapter should exist (dependency)
+        * To do so, we traverse through the core device, its adapter
+        * and the driver of its adapter, which requires the core
+        * device itself should be registered with the system
+        */
+       mutex_lock(&core_lock);
+       list_for_each_entry(d, &core_dev_list, node) {
+               if (!cyttsp4_match_core_device(d, drv->driver.name))
+                       continue;
+               if (d->adap) {
+                       if (d->adap->dev && d->adap->dev->driver) {
+                               ret = ref_module(drv->driver.owner,
+                                       d->adap->dev->driver->owner);
+                       } else {
+                               /* Core dev exist but not adap device
+                                * Do not let until adap module inserted */
+                               ret = -ENODEV;
+                       }
+               }
+               break;
+       }
+       mutex_unlock(&core_lock);
+
+       if (ret) {
+               if (ret == -ENODEV)
+                       pr_err("%s: Adapter driver module does not exist\n",
+                               __func__);
+               else
+                       pr_err("%s: Error getting ref to adapter driver module\n",
+                               __func__);
+               goto fail;
+       }
+#endif
+
+       drv->driver.bus = &cyttsp4_bus_type;
+       if (drv->probe)
+               drv->driver.probe = cyttsp4_core_drv_probe;
+       if (drv->remove)
+               drv->driver.remove = cyttsp4_core_drv_remove;
+       ret = driver_register(&drv->driver);
+fail:
+       pr_debug("%s: '%s' returned %d\n", __func__, drv->driver.name, ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cyttsp4_register_core_driver);
+
+void cyttsp4_unregister_driver(struct cyttsp4_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(cyttsp4_unregister_driver);
+
+void cyttsp4_unregister_core_driver(struct cyttsp4_core_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(cyttsp4_unregister_core_driver);
+
+int __init cyttsp4_bus_init(void)
+{
+       int error;
+       error =  bus_register(&cyttsp4_bus_type);
+       if (error)
+               pr_err("%s: error %d\n", __func__, error);
+       else
+               pr_debug("%s: ok\n", __func__);
+       return error;
+}
+
+static void __exit cyttsp4_bus_exit(void)
+{
+       pr_debug("%s: ok\n", __func__);
+}
+
+subsys_initcall(cyttsp4_bus_init);
+module_exit(cyttsp4_bus_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Aleksej Makarov <aleksej.makarov@...yericsson.com>");
diff --git a/include/linux/cyttsp4_bus.h b/include/linux/cyttsp4_bus.h
new file mode 100644
index 0000000..b1f64ef
--- /dev/null
+++ b/include/linux/cyttsp4_bus.h
@@ -0,0 +1,271 @@
+/*
+ * cyttsp4_bus.h
+ * Cypress TrueTouch(TM) Standard Product V4 Bus Driver.
+ * For use with Cypress Txx4xx parts.
+ * Supported parts include:
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2012 Cypress Semiconductor
+ * Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
+ *
+ * Author: Aleksej Makarov <aleksej.makarov@...yericsson.com>
+ * Modified by: Cypress Semiconductor to add device functions
+ *
+ * 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.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@...ress.com>
+ *
+ */
+
+#ifndef _LINUX_CYTTSP4_BUS_H
+#define _LINUX_CYTTSP4_BUS_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/limits.h>
+
+
+extern struct bus_type cyttsp4_bus_type;
+
+struct cyttsp4_driver;
+struct cyttsp4_device;
+struct cyttsp4_adapter;
+
+enum cyttsp4_atten_type {
+       CY_ATTEN_IRQ,
+       CY_ATTEN_STARTUP,
+       CY_ATTEN_EXCLUSIVE,
+       CY_ATTEN_NUM_ATTEN,
+};
+
+typedef int (*cyttsp4_atten_func) (struct cyttsp4_device *);
+
+struct cyttsp4_ops {
+       int (*write)(struct cyttsp4_adapter *dev, u8 addr,
+               const void *buf, int size);
+       int (*read)(struct cyttsp4_adapter *dev, u8 addr, void *buf, int size);
+};
+
+struct cyttsp4_adapter {
+       struct list_head node;
+       char id[NAME_MAX];
+       struct device *dev;
+       int (*write)(struct cyttsp4_adapter *dev, u8 addr,
+               const void *buf, int size);
+       int (*read)(struct cyttsp4_adapter *dev, u8 addr, void *buf, int size);
+};
+#define to_cyttsp4_adapter(d) container_of(d, struct cyttsp4_adapter, dev)
+
+struct cyttsp4_core {
+       struct list_head node;
+       char const *name;
+       char const *id;
+       char const *adap_id;
+       struct device dev;
+       struct cyttsp4_adapter *adap;
+};
+#define to_cyttsp4_core(d) container_of(d, struct cyttsp4_core, dev)
+
+struct cyttsp4_device {
+       struct list_head node;
+       char const *name;
+       char const *core_id;
+       struct device dev;
+       struct cyttsp4_core *core;
+};
+#define to_cyttsp4_device(d) container_of(d, struct cyttsp4_device, dev)
+
+struct cyttsp4_core_driver {
+       struct device_driver driver;
+       int (*probe)(struct cyttsp4_core *core);
+       int (*remove)(struct cyttsp4_core *core);
+       int (*subscribe_attention)(struct cyttsp4_device *ttsp,
+                               enum cyttsp4_atten_type type,
+                               cyttsp4_atten_func func,
+                               int flags);
+       int (*unsubscribe_attention)(struct cyttsp4_device *ttsp,
+                               enum cyttsp4_atten_type type,
+                               cyttsp4_atten_func func,
+                               int flags);
+       int (*request_exclusive)(struct cyttsp4_device *ttsp, int t);
+       int (*release_exclusive)(struct cyttsp4_device *ttsp);
+       int (*request_reset)(struct cyttsp4_device *ttsp);
+       int (*request_restart)(struct cyttsp4_device *ttsp);
+       int (*request_set_mode)(struct cyttsp4_device *ttsp, int mode);
+       struct cyttsp4_sysinfo *(*request_sysinfo)(struct cyttsp4_device *ttsp);
+       int (*request_handshake)(struct cyttsp4_device *ttsp, u8 mode);
+       int (*request_exec_cmd)(struct cyttsp4_device *ttsp, u8 mode,
+                       u8 *cmd_buf, size_t cmd_size, u8 *return_buf,
+                       size_t return_buf_size, int timeout);
+       int (*request_stop_wd)(struct cyttsp4_device *ttsp);
+       int (*request_toggle_lowpower)(struct cyttsp4_device *ttsp, u8 mode);
+       int (*write)(struct cyttsp4_device *ttsp, int mode,
+               u8 addr, const void *buf, int size);
+       int (*read)(struct cyttsp4_device *ttsp, int mode,
+               u8 addr, void *buf, int size);
+};
+#define to_cyttsp4_core_driver(d) \
+       container_of(d, struct cyttsp4_core_driver, driver)
+
+struct cyttsp4_driver {
+       struct device_driver driver;
+       int (*probe)(struct cyttsp4_device *dev);
+       int (*remove)(struct cyttsp4_device *fev);
+};
+#define to_cyttsp4_driver(d) container_of(d, struct cyttsp4_driver, driver)
+
+extern int cyttsp4_register_driver(struct cyttsp4_driver *drv);
+extern void cyttsp4_unregister_driver(struct cyttsp4_driver *drv);
+
+extern int cyttsp4_register_core_driver(struct cyttsp4_core_driver *drv);
+extern void cyttsp4_unregister_core_driver(struct cyttsp4_core_driver *drv);
+
+extern int cyttsp4_register_device(struct cyttsp4_device *pdev);
+extern void cyttsp4_unregister_device(struct cyttsp4_device *pdev);
+
+extern int cyttsp4_register_core_device(struct cyttsp4_core *pdev);
+
+extern int cyttsp4_add_adapter(char const *id, struct cyttsp4_ops const *ops,
+               struct device *parent);
+
+extern int cyttsp4_del_adapter(char const *id);
+
+static inline int cyttsp4_read(struct cyttsp4_device *ttsp, int mode, u8 addr,
+               void *buf, int size)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->read(ttsp, mode, addr, buf, size);
+}
+
+static inline int cyttsp4_write(struct cyttsp4_device *ttsp, int mode, u8 addr,
+               const void *buf, int size)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->write(ttsp, mode, addr, buf, size);
+}
+
+static inline int cyttsp4_adap_read(struct cyttsp4_adapter *adap, u8 addr,
+               void *buf, int size)
+{
+       return adap->read(adap, addr, buf, size);
+}
+
+static inline int cyttsp4_adap_write(struct cyttsp4_adapter *adap, u8 addr,
+               const void *buf, int size)
+{
+       return adap->write(adap, addr, buf, size);
+}
+
+static inline int cyttsp4_subscribe_attention(struct cyttsp4_device *ttsp,
+               enum cyttsp4_atten_type type, cyttsp4_atten_func func,
+               int flags)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->subscribe_attention(ttsp, type, func, flags);
+}
+
+static inline int cyttsp4_unsubscribe_attention(struct cyttsp4_device *ttsp,
+               enum cyttsp4_atten_type type, cyttsp4_atten_func func,
+               int flags)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->unsubscribe_attention(ttsp, type, func, flags);
+}
+
+static inline int cyttsp4_request_exclusive(struct cyttsp4_device *ttsp, int t)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->request_exclusive(ttsp, t);
+}
+
+static inline int cyttsp4_release_exclusive(struct cyttsp4_device *ttsp)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->release_exclusive(ttsp);
+}
+
+static inline int cyttsp4_request_reset(struct cyttsp4_device *ttsp)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->request_reset(ttsp);
+}
+
+static inline int cyttsp4_request_restart(struct cyttsp4_device *ttsp)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->request_restart(ttsp);
+}
+
+static inline int cyttsp4_request_set_mode(struct cyttsp4_device *ttsp,
+               int mode)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->request_set_mode(ttsp, mode);
+}
+
+static inline struct cyttsp4_sysinfo *cyttsp4_request_sysinfo(
+               struct cyttsp4_device *ttsp)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->request_sysinfo(ttsp);
+}
+
+static inline int cyttsp4_request_handshake(struct cyttsp4_device *ttsp,
+               u8 mode)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->request_handshake(ttsp, mode);
+}
+
+static inline int cyttsp4_request_exec_cmd(struct cyttsp4_device *ttsp,
+               u8 mode, u8 *cmd_buf, size_t cmd_size, u8 *return_buf,
+               size_t return_buf_size, int timeout)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->request_exec_cmd(ttsp, mode, cmd_buf, cmd_size, return_buf,
+                       return_buf_size, timeout);
+}
+
+static inline int cyttsp4_request_stop_wd(struct cyttsp4_device *ttsp)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->request_stop_wd(ttsp);
+}
+
+static inline int cyttsp4_request_toggle_lowpower(struct cyttsp4_device *ttsp,
+               u8 mode)
+{
+       struct cyttsp4_core *cd = ttsp->core;
+       struct cyttsp4_core_driver *d = to_cyttsp4_core_driver(cd->dev.driver);
+       return d->request_toggle_lowpower(ttsp, mode);
+}
+
+#endif /* _LINUX_CYTTSP4_BUS_H */
--
1.7.9.5


This message and any attachments may contain Cypress (or its subsidiaries) confidential information. If it has been received in error, please advise the sender and immediately delete this message.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ