From patchwork Mon May 5 09:04:33 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 29623 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pa0-f70.google.com (mail-pa0-f70.google.com [209.85.220.70]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id C62112055D for ; Mon, 5 May 2014 09:05:05 +0000 (UTC) Received: by mail-pa0-f70.google.com with SMTP id lj1sf16038423pab.5 for ; Mon, 05 May 2014 02:05:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe:content-type; bh=bu2bg5Hu5lxj+VGlR1HXkdxRy/2S0njee5vRU81FcVI=; b=Qwn+XLv2+H/O+dmGBFad0pXUvAfUWNPYc98dRALqBkRvLrdSyJjfkspyTfEoLM1kWg GA78GxZK2pmcrsxFDD0vnepzM1SbhbfM3JTKJNBVkpzzLJ4Ztsx2qlwbPxBDjhz+xATp RtyeDqPDu6h0bf0xSVvlL7mXRWeG2MKb4lwLfvLAwQ4tZ3YeHzQu2aSQiVdgcxcNA3qF voQffQFzUP96nKuhRpaDKHoA5NqLrxfgzRjQAthUtrobmERSPWF64B8lOmS+Is3KuX2p q190ak94FO9ZRHellVw3OdKGy2qvPM55srVKxOqM1vuU7DeLR5OOH+eJNUHMZf4xgk/K NW9w== X-Gm-Message-State: ALoCoQnF8Rz9YunX0Edzqutgcx5jvhh0swDiyqtscOWmmxsiXVZM5xg9VKzStOw4DTOzaPFNqu49 X-Received: by 10.66.240.4 with SMTP id vw4mr16171132pac.10.1399280704894; Mon, 05 May 2014 02:05:04 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.24.42 with SMTP id 39ls2291035qgq.26.gmail; Mon, 05 May 2014 02:05:04 -0700 (PDT) X-Received: by 10.52.166.102 with SMTP id zf6mr22747247vdb.2.1399280704735; Mon, 05 May 2014 02:05:04 -0700 (PDT) Received: from mail-vc0-f169.google.com (mail-vc0-f169.google.com [209.85.220.169]) by mx.google.com with ESMTPS id k4si1409972vcv.204.2014.05.05.02.05.04 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 05 May 2014 02:05:04 -0700 (PDT) Received-SPF: none (google.com: patch+caf_=patchwork-forward=linaro.org@linaro.org does not designate permitted sender hosts) client-ip=209.85.220.169; Received: by mail-vc0-f169.google.com with SMTP id ij19so1305865vcb.28 for ; Mon, 05 May 2014 02:05:04 -0700 (PDT) X-Received: by 10.58.186.71 with SMTP id fi7mr293233vec.32.1399280704639; Mon, 05 May 2014 02:05:04 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp124309vcb; Mon, 5 May 2014 02:05:04 -0700 (PDT) X-Received: by 10.50.32.70 with SMTP id g6mr21740379igi.0.1399280703866; Mon, 05 May 2014 02:05:03 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id pn4si7765545pac.462.2014.05.05.02.05.02; Mon, 05 May 2014 02:05:02 -0700 (PDT) Received-SPF: none (google.com: linux-kernel-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755598AbaEEJE5 (ORCPT + 27 others); Mon, 5 May 2014 05:04:57 -0400 Received: from arroyo.ext.ti.com ([192.94.94.40]:48022 "EHLO arroyo.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755555AbaEEJEw (ORCPT ); Mon, 5 May 2014 05:04:52 -0400 Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id s4594nq0012020; Mon, 5 May 2014 04:04:49 -0500 Received: from DFLE73.ent.ti.com (dfle73.ent.ti.com [128.247.5.110]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id s4594nPq012689; Mon, 5 May 2014 04:04:49 -0500 Received: from dlep32.itg.ti.com (157.170.170.100) by DFLE73.ent.ti.com (128.247.5.110) with Microsoft SMTP Server id 14.3.174.1; Mon, 5 May 2014 04:04:48 -0500 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id s4594ep1022901; Mon, 5 May 2014 04:04:46 -0500 From: Roger Quadros To: CC: , , , , , , , , Roger Quadros Subject: [PATCH v4 2/7] Input: pixcir_i2c_ts: Initialize interrupt mode and power mode Date: Mon, 5 May 2014 12:04:33 +0300 Message-ID: <1399280678-23925-3-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1399280678-23925-1-git-send-email-rogerq@ti.com> References: <1399280678-23925-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: rogerq@ti.com X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: patch+caf_=patchwork-forward=linaro.org@linaro.org does not designate permitted sender hosts) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Introduce helper functions to configure power and interrupt registers. Default to IDLE mode on probe as device supports auto wakeup to ACVIE mode on detecting finger touch. Configure interrupt mode and polarity on start up. Power down on device closure or module removal. Signed-off-by: Roger Quadros Acked-by: Mugunthan V N --- drivers/input/touchscreen/pixcir_i2c_ts.c | 176 +++++++++++++++++++++++++++++- include/linux/input/pixcir_ts.h | 42 +++++++ 2 files changed, 216 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 8a083bd..53d01d4 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -100,6 +100,164 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, + enum pixcir_power_mode mode) +{ + struct device *dev = &ts->client->dev; + int ret; + + ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE); + if (ret < 0) { + dev_err(dev, "%s: can't read reg 0x%x : %d\n", + __func__, PIXCIR_REG_POWER_MODE, ret); + return ret; + } + + ret &= ~PIXCIR_POWER_MODE_MASK; + ret |= mode; + + /* Always AUTO_IDLE */ + ret |= PIXCIR_POWER_ALLOW_IDLE; + + ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret); + if (ret < 0) { + dev_err(dev, "%s: can't write reg 0x%x : %d\n", + __func__, PIXCIR_REG_POWER_MODE, ret); + return ret; + } + + return 0; +} + +/* + * Set the interrupt mode for the device i.e. ATTB line behaviour + * + * @polarity : 1 for active high, 0 for active low. + */ +static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts, + enum pixcir_int_mode mode, + bool polarity) +{ + struct device *dev = &ts->client->dev; + int ret; + + ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); + if (ret < 0) { + dev_err(dev, "%s: can't read reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + ret &= ~PIXCIR_INT_MODE_MASK; + ret |= mode; + + if (polarity) + ret |= PIXCIR_INT_POL_HIGH; + else + ret &= ~PIXCIR_INT_POL_HIGH; + + ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); + if (ret < 0) { + dev_err(dev, "%s: can't write reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + return 0; +} + +/* + * Enable/disable interrupt generation + */ +static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable) +{ + struct device *dev = &ts->client->dev; + int ret; + + ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); + if (ret < 0) { + dev_err(dev, "%s: can't read reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + if (enable) + ret |= PIXCIR_INT_ENABLE; + else + ret &= ~PIXCIR_INT_ENABLE; + + ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); + if (ret < 0) { + dev_err(dev, "%s: can't write reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + return 0; +} + +static int pixcir_start(struct pixcir_i2c_ts_data *ts) +{ + struct device *dev = &ts->client->dev; + int ret; + + /* LEVEL_TOUCH interrupt with active low polarity */ + ret = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0); + if (ret) { + dev_err(dev, "Failed to set interrupt mode\n"); + return ret; + } + + ts->exiting = false; + mb(); /* Update status before IRQ can fire */ + + /* enable interrupt generation */ + ret = pixcir_int_enable(ts, 1); + if (ret) { + dev_err(dev, "Failed to enable interrupt generation\n"); + return ret; + } + + return 0; +} + +static int pixcir_stop(struct pixcir_i2c_ts_data *ts) +{ + struct device *dev = &ts->client->dev; + int ret; + + /* disable interrupt generation */ + ret = pixcir_int_enable(ts, 0); + if (ret) { + dev_err(dev, "Failed to disable interrupt generation\n"); + return ret; + } + + /* exit ISR if running, no more report parsing */ + ts->exiting = true; + mb(); /* update status before we synchronize irq */ + + /* wait till running ISR complete */ + synchronize_irq(ts->client->irq); + + return 0; +} + +static int pixcir_input_open(struct input_dev *dev) +{ + struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); + + return pixcir_start(ts); +} + +static void pixcir_input_close(struct input_dev *dev) +{ + struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); + + pixcir_stop(ts); +} + + #ifdef CONFIG_PM_SLEEP static int pixcir_i2c_ts_suspend(struct device *dev) { @@ -157,6 +315,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input->name = client->name; input->id.bustype = BUS_I2C; input->dev.parent = &client->dev; + input->open = pixcir_input_open; + input->close = pixcir_input_close; __set_bit(EV_KEY, input->evbit); __set_bit(EV_ABS, input->evbit); @@ -176,6 +336,18 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return error; } + /* Always be in IDLE mode to save power, device supports auto wake */ + error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE); + if (error) { + dev_err(dev, "Failed to set IDLE mode\n"); + return error; + } + + /* Stop device till opened */ + error = pixcir_stop(tsdata); + if (error) + return error; + error = input_register_device(input); if (error) return error; @@ -192,8 +364,8 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client) device_init_wakeup(&client->dev, 0); - tsdata->exiting = true; - mb(); + if (!tsdata->exiting) + pixcir_stop(tsdata); return 0; } diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h index 7163d91..7942804 100644 --- a/include/linux/input/pixcir_ts.h +++ b/include/linux/input/pixcir_ts.h @@ -1,6 +1,48 @@ #ifndef _PIXCIR_I2C_TS_H #define _PIXCIR_I2C_TS_H +/* + * Register map + */ +#define PIXCIR_REG_POWER_MODE 51 +#define PIXCIR_REG_INT_MODE 52 + +/* + * Power modes: + * active: max scan speed + * idle: lower scan speed with automatic transition to active on touch + * halt: datasheet says sleep but this is more like halt as the chip + * clocks are cut and it can only be brought out of this mode + * using the RESET pin. + */ +enum pixcir_power_mode { + PIXCIR_POWER_ACTIVE, + PIXCIR_POWER_IDLE, + PIXCIR_POWER_HALT, +}; + +#define PIXCIR_POWER_MODE_MASK 0x03 +#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2) + +/* + * Interrupt modes: + * periodical: interrupt is asserted periodicaly + * diff coordinates: interrupt is asserted when coordinates change + * level on touch: interrupt level asserted during touch + * pulse on touch: interrupt pulse asserted druing touch + * + */ +enum pixcir_int_mode { + PIXCIR_INT_PERIODICAL, + PIXCIR_INT_DIFF_COORD, + PIXCIR_INT_LEVEL_TOUCH, + PIXCIR_INT_PULSE_TOUCH, +}; + +#define PIXCIR_INT_MODE_MASK 0x03 +#define PIXCIR_INT_ENABLE (1UL << 3) +#define PIXCIR_INT_POL_HIGH (1UL << 2) + struct pixcir_ts_platform_data { int (*attb_read_val)(void); int x_max;