From: Shubhrajyoti <shubhrajyoti@ti.com>
To: Paul Parsons <lost.distance@yahoo.com>
Cc: linux-arm-kernel@lists.infradead.org,
linux-input@vger.kernel.org, philipp.zabel@gmail.com,
eric.y.miao@gmail.com, mad_soft@inbox.ru,
koen@dominion.thruhere.net, dmitry.torokhov@gmail.com
Subject: Re: [PATCH v5 1/2] pxa/hx4700: Add Synaptics NavPoint (PXA27x SSP/SPI) driver
Date: Mon, 02 Jan 2012 11:56:52 +0530 [thread overview]
Message-ID: <4F014E2C.4000402@ti.com> (raw)
In-Reply-To: <1325339211.59301.YahooMailClassic@web29007.mail.ird.yahoo.com>
Hi Paul,
Some minor comments / suggestions
On Saturday 31 December 2011 07:16 PM, Paul Parsons wrote:
> Add support for the Synaptics NavPoint touchpad connected to a PXA27x SSP port
> in SPI slave mode. The driver implements a simple navigation pad. The four
> raised dots are mapped to UP/DOWN/LEFT/RIGHT buttons and the centre of the
> touchpad is mapped to the ENTER button.
>
> Signed-off-by: Paul Parsons <lost.distance@yahoo.com>
> ---
>
> V5:
> Workaround for HaRET, which does not disable devices before jumping into Linux.
> Rebased to linux-3.2-rc7.
>
> diff -uprN clean-3.2-rc7/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h linux-3.2-rc7/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
> --- clean-3.2-rc7/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h 2011-12-24 05:51:06.000000000 +0000
> +++ linux-3.2-rc7/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h 2011-12-31 11:54:02.859594707 +0000
> @@ -206,6 +206,7 @@
> #define GPIO113_I2S_SYSCLK MFP_CFG_OUT(GPIO113, AF1, DRIVE_LOW)
>
> /* SSP 1 */
> +#define GPIO23_SSP1_SCLK_IN MFP_CFG_IN(GPIO23, AF2)
> #define GPIO23_SSP1_SCLK MFP_CFG_OUT(GPIO23, AF2, DRIVE_LOW)
> #define GPIO29_SSP1_SCLK MFP_CFG_IN(GPIO29, AF3)
> #define GPIO27_SSP1_SYSCLK MFP_CFG_OUT(GPIO27, AF1, DRIVE_LOW)
> diff -uprN clean-3.2-rc7/drivers/input/mouse/Kconfig linux-3.2-rc7/drivers/input/mouse/Kconfig
> --- clean-3.2-rc7/drivers/input/mouse/Kconfig 2011-12-24 05:51:06.000000000 +0000
> +++ linux-3.2-rc7/drivers/input/mouse/Kconfig 2011-12-31 11:54:02.859594707 +0000
> @@ -322,4 +322,13 @@ config MOUSE_SYNAPTICS_I2C
> To compile this driver as a module, choose M here: the
> module will be called synaptics_i2c.
>
> +config MOUSE_NAVPOINT_PXA27x
> + tristate "Synaptics NavPoint (PXA27x SSP/SPI)"
> + depends on PXA27x && PXA_SSP
> + help
> + This option enables support for the Synaptics NavPoint connected to
> + a PXA27x SSP port in SPI slave mode. The driver implements a simple
> + navigation pad. The four raised dots are mapped to UP/DOWN/LEFT/RIGHT
> + buttons and the centre of the touchpad is mapped to the ENTER button.
Maybe some help on module building as tristate.
> +
> endif
> diff -uprN clean-3.2-rc7/drivers/input/mouse/Makefile linux-3.2-rc7/drivers/input/mouse/Makefile
> --- clean-3.2-rc7/drivers/input/mouse/Makefile 2011-12-24 05:51:06.000000000 +0000
> +++ linux-3.2-rc7/drivers/input/mouse/Makefile 2011-12-31 11:54:02.859594707 +0000
> @@ -12,6 +12,7 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.
> obj-$(CONFIG_MOUSE_INPORT) += inport.o
> obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
> obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
> +obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x) += navpoint.o
> obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
> obj-$(CONFIG_MOUSE_PS2) += psmouse.o
> obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o
> diff -uprN clean-3.2-rc7/drivers/input/mouse/navpoint.c linux-3.2-rc7/drivers/input/mouse/navpoint.c
> --- clean-3.2-rc7/drivers/input/mouse/navpoint.c 1970-01-01 01:00:00.000000000 +0100
> +++ linux-3.2-rc7/drivers/input/mouse/navpoint.c 2011-12-31 11:58:45.563587396 +0000
> @@ -0,0 +1,337 @@
> +/*
> + * Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/gpio.h>
> +#include <linux/input.h>
> +#include <linux/input/navpoint.h>
> +#include <linux/interrupt.h>
> +#include <linux/pxa2xx_ssp.h>
> +#include <linux/slab.h>
> +
> +/*
> + * Synaptics NavPoint (PXA27x SSP/SPI) driver.
> + */
> +
> +/*
> + * Synaptics Modular Embedded Protocol: Module Packet Format.
> + * Module header byte 2:0 = Length (# bytes that follow)
> + * Module header byte 4:3 = Control
> + * Module header byte 7:5 = Module Address
> + */
> +#define HEADER_LENGTH(byte) ((byte) & 0x07)
> +#define HEADER_CONTROL(byte) (((byte) >> 3) & 0x03)
> +#define HEADER_ADDRESS(byte) ((byte) >> 5)
> +
> +struct driver_data {
> + struct ssp_device *ssp;
> + int gpio;
> + struct input_dev *input;
> + int index;
> + uint8_t data[1+HEADER_LENGTH(0xff)];
> + int pressed; /* 1 = pressed, 0 = released */
Could this be bool ?
> + unsigned code; /* Code of last key pressed */
> +};
> +
> +static const u32 sscr0 = 0
> + | SSCR0_TUM /* TIM = 1; No TUR interrupts */
> + | SSCR0_RIM /* RIM = 1; No ROR interrupts */
> + | SSCR0_SSE /* SSE = 1; SSP enabled */
> + | SSCR0_Motorola /* FRF = 0; Motorola SPI */
> + | SSCR0_DataSize(16) /* DSS = 15; Data size = 16-bit */
> + ;
> +static const u32 sscr1 = 0
> + | SSCR1_SCFR /* SCFR = 1; SSPSCLK only during transfers */
> + | SSCR1_SCLKDIR /* SCLKDIR = 1; Slave mode */
> + | SSCR1_SFRMDIR /* SFRMDIR = 1; Slave mode */
> + | SSCR1_RWOT /* RWOT = 1; Receive without transmit mode */
> + | SSCR1_RxTresh(1) /* RFT = 0; Receive FIFO threshold = 1 */
> + | SSCR1_SPH /* SPH = 1; SSPSCLK inactive 0.5 + 1 cycles */
> + | SSCR1_RIE /* RIE = 1; Receive FIFO interrupt enabled */
> + ;
> +static const u32 sssr = 0
> + | SSSR_BCE /* BCE = 1; Clear BCE */
> + | SSSR_TUR /* TUR = 1; Clear TUR */
> + | SSSR_EOC /* EOC = 1; Clear EOC */
> + | SSSR_TINT /* TINT = 1; Clear TINT */
> + | SSSR_PINT /* PINT = 1; Clear PINT */
> + | SSSR_ROR /* ROR = 1; Clear ROR */
> + ;
> +
> +/*
> + * MEP Query $22: Touchpad Coordinate Range Query is not supported by
> + * the NavPoint module, so sampled values provide the default limits.
> + */
> +
> +static int west = 2416; /* 1/3 width */
> +module_param(west, int, 0644);
> +MODULE_PARM_DESC(west, "X coordinate limit for KEY_LEFT. Default = 2416");
> +static int east = 3904; /* 2/3 width */
> +module_param(east, int, 0644);
> +MODULE_PARM_DESC(east, "X coordinate limit for KEY_RIGHT. Default = 3904");
> +static int south = 2480; /* 1/3 height */
> +module_param(south, int, 0644);
> +MODULE_PARM_DESC(south, "Y coordinate limit for KEY_DOWN. Default = 2480");
> +static int north = 3424; /* 2/3 height */
> +module_param(north, int, 0644);
> +MODULE_PARM_DESC(north, "Y coordinate limit for KEY_UP. Default = 3424");
> +
> +static void navpoint_packet(struct device *dev)
> +{
> + struct driver_data *drv_data = dev_get_drvdata(dev);
> + int pressed;
> + unsigned x, y;
> + unsigned code;
> +
> + switch (drv_data->data[0]) {
> + case 0xff: /* Garbage (packet?) between reset and Hello packet */
> + case 0x00: /* Module 0, NULL packet */
> + break;
> + case 0x0e: /* Module 0, Absolute packet */
> + pressed = (drv_data->data[1] & 0x01);
> + if ((drv_data->pressed ^ pressed) == 0) /* No change */
> + break;
> + drv_data->pressed = pressed;
> + x = ((drv_data->data[2] & 0x1f) << 8) | drv_data->data[3];
> + y = ((drv_data->data[4] & 0x1f) << 8) | drv_data->data[5];
> + if (x < west)
> + code = KEY_LEFT;
> + else if (x > east)
> + code = KEY_RIGHT;
> + else if (y < south)
> + code = KEY_DOWN;
> + else if (y > north)
> + code = KEY_UP;
> + else
> + code = KEY_ENTER;
> + if (pressed)
> + drv_data->code = code;
> + input_report_key(drv_data->input, drv_data->code, pressed);
> + input_sync(drv_data->input);
> + break;
> + case 0x19: /* Module 0, Hello packet */
> + if ((drv_data->data[1] & 0xf0) == 0x10)
> + break;
> + /* FALLTHROUGH */
> + default:
> + dev_warn(dev, "spurious packet: 0x%02x,0x%02x,...\n",
> + drv_data->data[0],
> + drv_data->data[1]);
> + break;
> + }
> +
> + drv_data->index = 0;
> +}
> +
> +static irqreturn_t navpoint_int(int irq, void *dev_id)
> +{
> + struct device *dev = dev_id;
> + struct driver_data *drv_data = dev_get_drvdata(dev);
> + struct ssp_device *ssp = drv_data->ssp;
> + u32 status;
> + irqreturn_t ret;
> +
> + status = pxa_ssp_read_reg(ssp, SSSR);
> + ret = IRQ_NONE;
> +
> + if (status & sssr) {
> + dev_warn(dev, "spurious interrupt: 0x%02x\n", status);
> + pxa_ssp_write_reg(ssp, SSSR, (status & sssr));
> + ret = IRQ_HANDLED;
> + }
> +
> + if (status & SSSR_RFS) {
> + while (status & SSSR_RNE) {
> + u32 data;
> +
> + data = pxa_ssp_read_reg(ssp, SSDR);
> + drv_data->data[drv_data->index + 0] = (data >> 8);
> + drv_data->data[drv_data->index + 1] = data;
> + drv_data->index += 2;
> + if (HEADER_LENGTH(drv_data->data[0]) < drv_data->index)
> + navpoint_packet(dev);
> + status = pxa_ssp_read_reg(ssp, SSSR);
> + }
> + ret = IRQ_HANDLED;
> + }
> +
> + return ret;
> +}
> +
> +static int navpoint_suspend(struct device *dev)
> +{
> + struct driver_data *drv_data = dev_get_drvdata(dev);
> + struct ssp_device *ssp = drv_data->ssp;
> +
> + gpio_set_value(drv_data->gpio, 0);
> +
> + pxa_ssp_write_reg(ssp, SSCR0, 0);
> +
> + clk_disable(ssp->clk);
> +
> + return 0;
> +}
> +
> +static int navpoint_resume(struct device *dev)
> +{
> + struct driver_data *drv_data = dev_get_drvdata(dev);
> + struct ssp_device *ssp = drv_data->ssp;
> + int timeout;
> +
> + clk_enable(ssp->clk);
> +
> + pxa_ssp_write_reg(ssp, SSCR1, sscr1);
> + pxa_ssp_write_reg(ssp, SSSR, sssr);
> + pxa_ssp_write_reg(ssp, SSTO, 0);
> + pxa_ssp_write_reg(ssp, SSCR0, sscr0); /* SSCR0_SSE written last */
> +
> + /* Wait until SSP port is ready for slave clock operations */
> + for (timeout = 100; timeout != 0; --timeout) {
> + if (!(pxa_ssp_read_reg(ssp, SSSR) & SSSR_CSS))
> + break;
> + msleep(1);
> + }
> + if (timeout == 0)
> + dev_err(dev, "timeout waiting for SSSR[CSS] to clear\n");
> +
> + gpio_set_value(drv_data->gpio, 1);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_SUSPEND
> +static const struct dev_pm_ops navpoint_pm_ops = {
> + .suspend = navpoint_suspend,
> + .resume = navpoint_resume,
> +};
> +#endif
> +
> +static int __devinit navpoint_probe(struct platform_device *pdev)
> +{
> + struct navpoint_platform_data *pdata = pdev->dev.platform_data;
> + int ret;
> + struct driver_data *drv_data;
> + struct ssp_device *ssp;
> + struct input_dev *input;
> +
> + drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
> + if (!drv_data) {
> + ret = -ENOMEM;
> + goto ret0;
> + }
> +
> + ssp = pxa_ssp_request(pdata->port, pdev->name);
> + if (!ssp) {
> + ret = -ENODEV;
> + goto ret1;
> + }
> +
> + /* HaRET does not disable devices before jumping into Linux */
> + if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
> + gpio_set_value(pdata->gpio, 0);
> + pxa_ssp_write_reg(ssp, SSCR0, 0);
> + dev_warn(&pdev->dev, "ssp%d already enabled\n", pdata->port);
> + }
> +
> + input = input_allocate_device();
> + if (!input) {
> + ret = -ENOMEM;
> + goto ret2;
> + }
> + input->name = pdev->name;
> + __set_bit(EV_KEY, input->evbit);
> + __set_bit(KEY_ENTER, input->keybit);
> + __set_bit(KEY_UP, input->keybit);
> + __set_bit(KEY_LEFT, input->keybit);
> + __set_bit(KEY_RIGHT, input->keybit);
> + __set_bit(KEY_DOWN, input->keybit);
> + input->dev.parent = &pdev->dev;
> + ret = input_register_device(input);
> + if (ret) {
> + input_free_device(input);
> + goto ret2;
> + }
> +
> + drv_data->ssp = ssp;
> + drv_data->gpio = pdata->gpio;
> + drv_data->input = input;
> +
> + platform_set_drvdata(pdev, drv_data);
> +
> + ret = request_irq(ssp->irq, navpoint_int, 0, pdev->name, &pdev->dev);
Could this be a threadded irq?
> + if (ret)
> + goto ret3;
> +
> + navpoint_resume(&pdev->dev);
Could this be pushed to open instead?
> +
> + dev_info(&pdev->dev, "ssp%d, irq %d\n", pdata->port, ssp->irq);
> +
> + return 0;
> +
> +ret3:
> + input_unregister_device(input);
> +ret2:
> + pxa_ssp_free(ssp);
> +ret1:
> + kfree(drv_data);
> +ret0:
> + return ret;
> +}
> +
> +static int __devexit navpoint_remove(struct platform_device *pdev)
> +{
> + struct driver_data *drv_data = platform_get_drvdata(pdev);
> + struct ssp_device *ssp = drv_data->ssp;
> + struct input_dev *input = drv_data->input;
> +
> + navpoint_suspend(&pdev->dev);
> +
> + free_irq(ssp->irq, drv_data);
> +
> + input_unregister_device(input);
> +
> + pxa_ssp_free(ssp);
> +
> + kfree(drv_data);
> +
> + return 0;
> +}
> +
> +static struct platform_driver navpoint_driver = {
> + .probe = navpoint_probe,
> + .remove = __devexit_p(navpoint_remove),
> + .driver = {
> + .name = "navpoint",
> + .owner = THIS_MODULE,
> +#ifdef CONFIG_SUSPEND
> + .pm = &navpoint_pm_ops,
> +#endif
> + },
> +};
> +
> +static int __init navpoint_init(void)
> +{
> + return platform_driver_register(&navpoint_driver);
> +}
> +
> +static void __exit navpoint_exit(void)
> +{
> + platform_driver_unregister(&navpoint_driver);
> +}
> +
> +module_init(navpoint_init);
> +module_exit(navpoint_exit);
> +
> +MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
> +MODULE_DESCRIPTION("Synaptics NavPoint (PXA27x SSP/SPI) driver");
> +MODULE_LICENSE("GPL");
> diff -uprN clean-3.2-rc7/include/linux/input/navpoint.h linux-3.2-rc7/include/linux/input/navpoint.h
> --- clean-3.2-rc7/include/linux/input/navpoint.h 1970-01-01 01:00:00.000000000 +0100
> +++ linux-3.2-rc7/include/linux/input/navpoint.h 2011-12-31 11:54:02.859594707 +0000
> @@ -0,0 +1,12 @@
> +/*
> + * Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +struct navpoint_platform_data {
> + int port; /* PXA SSP port for pxa_ssp_request() */
> + int gpio; /* GPIO for power on/off */
> +};
>
> --
> 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
WARNING: multiple messages have this Message-ID (diff)
From: shubhrajyoti@ti.com (Shubhrajyoti)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v5 1/2] pxa/hx4700: Add Synaptics NavPoint (PXA27x SSP/SPI) driver
Date: Mon, 02 Jan 2012 11:56:52 +0530 [thread overview]
Message-ID: <4F014E2C.4000402@ti.com> (raw)
In-Reply-To: <1325339211.59301.YahooMailClassic@web29007.mail.ird.yahoo.com>
Hi Paul,
Some minor comments / suggestions
On Saturday 31 December 2011 07:16 PM, Paul Parsons wrote:
> Add support for the Synaptics NavPoint touchpad connected to a PXA27x SSP port
> in SPI slave mode. The driver implements a simple navigation pad. The four
> raised dots are mapped to UP/DOWN/LEFT/RIGHT buttons and the centre of the
> touchpad is mapped to the ENTER button.
>
> Signed-off-by: Paul Parsons <lost.distance@yahoo.com>
> ---
>
> V5:
> Workaround for HaRET, which does not disable devices before jumping into Linux.
> Rebased to linux-3.2-rc7.
>
> diff -uprN clean-3.2-rc7/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h linux-3.2-rc7/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
> --- clean-3.2-rc7/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h 2011-12-24 05:51:06.000000000 +0000
> +++ linux-3.2-rc7/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h 2011-12-31 11:54:02.859594707 +0000
> @@ -206,6 +206,7 @@
> #define GPIO113_I2S_SYSCLK MFP_CFG_OUT(GPIO113, AF1, DRIVE_LOW)
>
> /* SSP 1 */
> +#define GPIO23_SSP1_SCLK_IN MFP_CFG_IN(GPIO23, AF2)
> #define GPIO23_SSP1_SCLK MFP_CFG_OUT(GPIO23, AF2, DRIVE_LOW)
> #define GPIO29_SSP1_SCLK MFP_CFG_IN(GPIO29, AF3)
> #define GPIO27_SSP1_SYSCLK MFP_CFG_OUT(GPIO27, AF1, DRIVE_LOW)
> diff -uprN clean-3.2-rc7/drivers/input/mouse/Kconfig linux-3.2-rc7/drivers/input/mouse/Kconfig
> --- clean-3.2-rc7/drivers/input/mouse/Kconfig 2011-12-24 05:51:06.000000000 +0000
> +++ linux-3.2-rc7/drivers/input/mouse/Kconfig 2011-12-31 11:54:02.859594707 +0000
> @@ -322,4 +322,13 @@ config MOUSE_SYNAPTICS_I2C
> To compile this driver as a module, choose M here: the
> module will be called synaptics_i2c.
>
> +config MOUSE_NAVPOINT_PXA27x
> + tristate "Synaptics NavPoint (PXA27x SSP/SPI)"
> + depends on PXA27x && PXA_SSP
> + help
> + This option enables support for the Synaptics NavPoint connected to
> + a PXA27x SSP port in SPI slave mode. The driver implements a simple
> + navigation pad. The four raised dots are mapped to UP/DOWN/LEFT/RIGHT
> + buttons and the centre of the touchpad is mapped to the ENTER button.
Maybe some help on module building as tristate.
> +
> endif
> diff -uprN clean-3.2-rc7/drivers/input/mouse/Makefile linux-3.2-rc7/drivers/input/mouse/Makefile
> --- clean-3.2-rc7/drivers/input/mouse/Makefile 2011-12-24 05:51:06.000000000 +0000
> +++ linux-3.2-rc7/drivers/input/mouse/Makefile 2011-12-31 11:54:02.859594707 +0000
> @@ -12,6 +12,7 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.
> obj-$(CONFIG_MOUSE_INPORT) += inport.o
> obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
> obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
> +obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x) += navpoint.o
> obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
> obj-$(CONFIG_MOUSE_PS2) += psmouse.o
> obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o
> diff -uprN clean-3.2-rc7/drivers/input/mouse/navpoint.c linux-3.2-rc7/drivers/input/mouse/navpoint.c
> --- clean-3.2-rc7/drivers/input/mouse/navpoint.c 1970-01-01 01:00:00.000000000 +0100
> +++ linux-3.2-rc7/drivers/input/mouse/navpoint.c 2011-12-31 11:58:45.563587396 +0000
> @@ -0,0 +1,337 @@
> +/*
> + * Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/gpio.h>
> +#include <linux/input.h>
> +#include <linux/input/navpoint.h>
> +#include <linux/interrupt.h>
> +#include <linux/pxa2xx_ssp.h>
> +#include <linux/slab.h>
> +
> +/*
> + * Synaptics NavPoint (PXA27x SSP/SPI) driver.
> + */
> +
> +/*
> + * Synaptics Modular Embedded Protocol: Module Packet Format.
> + * Module header byte 2:0 = Length (# bytes that follow)
> + * Module header byte 4:3 = Control
> + * Module header byte 7:5 = Module Address
> + */
> +#define HEADER_LENGTH(byte) ((byte) & 0x07)
> +#define HEADER_CONTROL(byte) (((byte) >> 3) & 0x03)
> +#define HEADER_ADDRESS(byte) ((byte) >> 5)
> +
> +struct driver_data {
> + struct ssp_device *ssp;
> + int gpio;
> + struct input_dev *input;
> + int index;
> + uint8_t data[1+HEADER_LENGTH(0xff)];
> + int pressed; /* 1 = pressed, 0 = released */
Could this be bool ?
> + unsigned code; /* Code of last key pressed */
> +};
> +
> +static const u32 sscr0 = 0
> + | SSCR0_TUM /* TIM = 1; No TUR interrupts */
> + | SSCR0_RIM /* RIM = 1; No ROR interrupts */
> + | SSCR0_SSE /* SSE = 1; SSP enabled */
> + | SSCR0_Motorola /* FRF = 0; Motorola SPI */
> + | SSCR0_DataSize(16) /* DSS = 15; Data size = 16-bit */
> + ;
> +static const u32 sscr1 = 0
> + | SSCR1_SCFR /* SCFR = 1; SSPSCLK only during transfers */
> + | SSCR1_SCLKDIR /* SCLKDIR = 1; Slave mode */
> + | SSCR1_SFRMDIR /* SFRMDIR = 1; Slave mode */
> + | SSCR1_RWOT /* RWOT = 1; Receive without transmit mode */
> + | SSCR1_RxTresh(1) /* RFT = 0; Receive FIFO threshold = 1 */
> + | SSCR1_SPH /* SPH = 1; SSPSCLK inactive 0.5 + 1 cycles */
> + | SSCR1_RIE /* RIE = 1; Receive FIFO interrupt enabled */
> + ;
> +static const u32 sssr = 0
> + | SSSR_BCE /* BCE = 1; Clear BCE */
> + | SSSR_TUR /* TUR = 1; Clear TUR */
> + | SSSR_EOC /* EOC = 1; Clear EOC */
> + | SSSR_TINT /* TINT = 1; Clear TINT */
> + | SSSR_PINT /* PINT = 1; Clear PINT */
> + | SSSR_ROR /* ROR = 1; Clear ROR */
> + ;
> +
> +/*
> + * MEP Query $22: Touchpad Coordinate Range Query is not supported by
> + * the NavPoint module, so sampled values provide the default limits.
> + */
> +
> +static int west = 2416; /* 1/3 width */
> +module_param(west, int, 0644);
> +MODULE_PARM_DESC(west, "X coordinate limit for KEY_LEFT. Default = 2416");
> +static int east = 3904; /* 2/3 width */
> +module_param(east, int, 0644);
> +MODULE_PARM_DESC(east, "X coordinate limit for KEY_RIGHT. Default = 3904");
> +static int south = 2480; /* 1/3 height */
> +module_param(south, int, 0644);
> +MODULE_PARM_DESC(south, "Y coordinate limit for KEY_DOWN. Default = 2480");
> +static int north = 3424; /* 2/3 height */
> +module_param(north, int, 0644);
> +MODULE_PARM_DESC(north, "Y coordinate limit for KEY_UP. Default = 3424");
> +
> +static void navpoint_packet(struct device *dev)
> +{
> + struct driver_data *drv_data = dev_get_drvdata(dev);
> + int pressed;
> + unsigned x, y;
> + unsigned code;
> +
> + switch (drv_data->data[0]) {
> + case 0xff: /* Garbage (packet?) between reset and Hello packet */
> + case 0x00: /* Module 0, NULL packet */
> + break;
> + case 0x0e: /* Module 0, Absolute packet */
> + pressed = (drv_data->data[1] & 0x01);
> + if ((drv_data->pressed ^ pressed) == 0) /* No change */
> + break;
> + drv_data->pressed = pressed;
> + x = ((drv_data->data[2] & 0x1f) << 8) | drv_data->data[3];
> + y = ((drv_data->data[4] & 0x1f) << 8) | drv_data->data[5];
> + if (x < west)
> + code = KEY_LEFT;
> + else if (x > east)
> + code = KEY_RIGHT;
> + else if (y < south)
> + code = KEY_DOWN;
> + else if (y > north)
> + code = KEY_UP;
> + else
> + code = KEY_ENTER;
> + if (pressed)
> + drv_data->code = code;
> + input_report_key(drv_data->input, drv_data->code, pressed);
> + input_sync(drv_data->input);
> + break;
> + case 0x19: /* Module 0, Hello packet */
> + if ((drv_data->data[1] & 0xf0) == 0x10)
> + break;
> + /* FALLTHROUGH */
> + default:
> + dev_warn(dev, "spurious packet: 0x%02x,0x%02x,...\n",
> + drv_data->data[0],
> + drv_data->data[1]);
> + break;
> + }
> +
> + drv_data->index = 0;
> +}
> +
> +static irqreturn_t navpoint_int(int irq, void *dev_id)
> +{
> + struct device *dev = dev_id;
> + struct driver_data *drv_data = dev_get_drvdata(dev);
> + struct ssp_device *ssp = drv_data->ssp;
> + u32 status;
> + irqreturn_t ret;
> +
> + status = pxa_ssp_read_reg(ssp, SSSR);
> + ret = IRQ_NONE;
> +
> + if (status & sssr) {
> + dev_warn(dev, "spurious interrupt: 0x%02x\n", status);
> + pxa_ssp_write_reg(ssp, SSSR, (status & sssr));
> + ret = IRQ_HANDLED;
> + }
> +
> + if (status & SSSR_RFS) {
> + while (status & SSSR_RNE) {
> + u32 data;
> +
> + data = pxa_ssp_read_reg(ssp, SSDR);
> + drv_data->data[drv_data->index + 0] = (data >> 8);
> + drv_data->data[drv_data->index + 1] = data;
> + drv_data->index += 2;
> + if (HEADER_LENGTH(drv_data->data[0]) < drv_data->index)
> + navpoint_packet(dev);
> + status = pxa_ssp_read_reg(ssp, SSSR);
> + }
> + ret = IRQ_HANDLED;
> + }
> +
> + return ret;
> +}
> +
> +static int navpoint_suspend(struct device *dev)
> +{
> + struct driver_data *drv_data = dev_get_drvdata(dev);
> + struct ssp_device *ssp = drv_data->ssp;
> +
> + gpio_set_value(drv_data->gpio, 0);
> +
> + pxa_ssp_write_reg(ssp, SSCR0, 0);
> +
> + clk_disable(ssp->clk);
> +
> + return 0;
> +}
> +
> +static int navpoint_resume(struct device *dev)
> +{
> + struct driver_data *drv_data = dev_get_drvdata(dev);
> + struct ssp_device *ssp = drv_data->ssp;
> + int timeout;
> +
> + clk_enable(ssp->clk);
> +
> + pxa_ssp_write_reg(ssp, SSCR1, sscr1);
> + pxa_ssp_write_reg(ssp, SSSR, sssr);
> + pxa_ssp_write_reg(ssp, SSTO, 0);
> + pxa_ssp_write_reg(ssp, SSCR0, sscr0); /* SSCR0_SSE written last */
> +
> + /* Wait until SSP port is ready for slave clock operations */
> + for (timeout = 100; timeout != 0; --timeout) {
> + if (!(pxa_ssp_read_reg(ssp, SSSR) & SSSR_CSS))
> + break;
> + msleep(1);
> + }
> + if (timeout == 0)
> + dev_err(dev, "timeout waiting for SSSR[CSS] to clear\n");
> +
> + gpio_set_value(drv_data->gpio, 1);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_SUSPEND
> +static const struct dev_pm_ops navpoint_pm_ops = {
> + .suspend = navpoint_suspend,
> + .resume = navpoint_resume,
> +};
> +#endif
> +
> +static int __devinit navpoint_probe(struct platform_device *pdev)
> +{
> + struct navpoint_platform_data *pdata = pdev->dev.platform_data;
> + int ret;
> + struct driver_data *drv_data;
> + struct ssp_device *ssp;
> + struct input_dev *input;
> +
> + drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
> + if (!drv_data) {
> + ret = -ENOMEM;
> + goto ret0;
> + }
> +
> + ssp = pxa_ssp_request(pdata->port, pdev->name);
> + if (!ssp) {
> + ret = -ENODEV;
> + goto ret1;
> + }
> +
> + /* HaRET does not disable devices before jumping into Linux */
> + if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
> + gpio_set_value(pdata->gpio, 0);
> + pxa_ssp_write_reg(ssp, SSCR0, 0);
> + dev_warn(&pdev->dev, "ssp%d already enabled\n", pdata->port);
> + }
> +
> + input = input_allocate_device();
> + if (!input) {
> + ret = -ENOMEM;
> + goto ret2;
> + }
> + input->name = pdev->name;
> + __set_bit(EV_KEY, input->evbit);
> + __set_bit(KEY_ENTER, input->keybit);
> + __set_bit(KEY_UP, input->keybit);
> + __set_bit(KEY_LEFT, input->keybit);
> + __set_bit(KEY_RIGHT, input->keybit);
> + __set_bit(KEY_DOWN, input->keybit);
> + input->dev.parent = &pdev->dev;
> + ret = input_register_device(input);
> + if (ret) {
> + input_free_device(input);
> + goto ret2;
> + }
> +
> + drv_data->ssp = ssp;
> + drv_data->gpio = pdata->gpio;
> + drv_data->input = input;
> +
> + platform_set_drvdata(pdev, drv_data);
> +
> + ret = request_irq(ssp->irq, navpoint_int, 0, pdev->name, &pdev->dev);
Could this be a threadded irq?
> + if (ret)
> + goto ret3;
> +
> + navpoint_resume(&pdev->dev);
Could this be pushed to open instead?
> +
> + dev_info(&pdev->dev, "ssp%d, irq %d\n", pdata->port, ssp->irq);
> +
> + return 0;
> +
> +ret3:
> + input_unregister_device(input);
> +ret2:
> + pxa_ssp_free(ssp);
> +ret1:
> + kfree(drv_data);
> +ret0:
> + return ret;
> +}
> +
> +static int __devexit navpoint_remove(struct platform_device *pdev)
> +{
> + struct driver_data *drv_data = platform_get_drvdata(pdev);
> + struct ssp_device *ssp = drv_data->ssp;
> + struct input_dev *input = drv_data->input;
> +
> + navpoint_suspend(&pdev->dev);
> +
> + free_irq(ssp->irq, drv_data);
> +
> + input_unregister_device(input);
> +
> + pxa_ssp_free(ssp);
> +
> + kfree(drv_data);
> +
> + return 0;
> +}
> +
> +static struct platform_driver navpoint_driver = {
> + .probe = navpoint_probe,
> + .remove = __devexit_p(navpoint_remove),
> + .driver = {
> + .name = "navpoint",
> + .owner = THIS_MODULE,
> +#ifdef CONFIG_SUSPEND
> + .pm = &navpoint_pm_ops,
> +#endif
> + },
> +};
> +
> +static int __init navpoint_init(void)
> +{
> + return platform_driver_register(&navpoint_driver);
> +}
> +
> +static void __exit navpoint_exit(void)
> +{
> + platform_driver_unregister(&navpoint_driver);
> +}
> +
> +module_init(navpoint_init);
> +module_exit(navpoint_exit);
> +
> +MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
> +MODULE_DESCRIPTION("Synaptics NavPoint (PXA27x SSP/SPI) driver");
> +MODULE_LICENSE("GPL");
> diff -uprN clean-3.2-rc7/include/linux/input/navpoint.h linux-3.2-rc7/include/linux/input/navpoint.h
> --- clean-3.2-rc7/include/linux/input/navpoint.h 1970-01-01 01:00:00.000000000 +0100
> +++ linux-3.2-rc7/include/linux/input/navpoint.h 2011-12-31 11:54:02.859594707 +0000
> @@ -0,0 +1,12 @@
> +/*
> + * Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +struct navpoint_platform_data {
> + int port; /* PXA SSP port for pxa_ssp_request() */
> + int gpio; /* GPIO for power on/off */
> +};
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2012-01-02 6:27 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-31 13:46 [PATCH v5 1/2] pxa/hx4700: Add Synaptics NavPoint (PXA27x SSP/SPI) driver Paul Parsons
2011-12-31 13:46 ` Paul Parsons
2012-01-02 6:26 ` Shubhrajyoti [this message]
2012-01-02 6:26 ` Shubhrajyoti
2012-01-04 16:21 ` Paul Parsons
2012-01-04 16:21 ` Paul Parsons
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4F014E2C.4000402@ti.com \
--to=shubhrajyoti@ti.com \
--cc=dmitry.torokhov@gmail.com \
--cc=eric.y.miao@gmail.com \
--cc=koen@dominion.thruhere.net \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-input@vger.kernel.org \
--cc=lost.distance@yahoo.com \
--cc=mad_soft@inbox.ru \
--cc=philipp.zabel@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.