From patchwork Tue Aug 7 13:09:30 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ferruh Yigit X-Patchwork-Id: 1285661 Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id D1674DF280 for ; Tue, 7 Aug 2012 13:15:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754684Ab2HGNPF (ORCPT ); Tue, 7 Aug 2012 09:15:05 -0400 Received: from relay.ihostexchange.net ([66.46.182.57]:12718 "EHLO relay.ihostexchange.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753661Ab2HGNPE convert rfc822-to-8bit (ORCPT ); Tue, 7 Aug 2012 09:15:04 -0400 X-Greylist: delayed 307 seconds by postgrey-1.27 at vger.kernel.org; Tue, 07 Aug 2012 09:15:03 EDT Received: from ferruhy-laptop.cypress.com (157.95.211.50) by smtp.ihostexchange.net (66.46.182.50) with Microsoft SMTP Server (TLS) id 8.3.213.0; Tue, 7 Aug 2012 09:09:51 -0400 From: Ferruh Yigit To: Dmitry Torokhov CC: Kevin McNeely , Ferruh YIGIT , Javier Martinez Canillas , Henrik Rydberg , Shawn Landden , Ashish Jangam , Olivier Sobrie , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/4] Input: cyttsp4 - bus driver for Cypress TMA4XX touchscreen devices Date: Tue, 7 Aug 2012 16:09:30 +0300 Message-ID: <1344344978-30453-1-git-send-email-fery@cypress.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org From: Ferruh YIGIT 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 --- 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 -- 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-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html 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@sonyericsson.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 + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +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 "); 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 + * 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 + * + */ + +#ifndef _LINUX_CYTTSP4_BUS_H +#define _LINUX_CYTTSP4_BUS_H + +#include +#include +#include +#include +#include + + +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 */