Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,305 @@
/*
* Touchscreen driver for Marvell 88PM860x
*
* Copyright (C) 2009 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.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/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/mfd/88pm860x.h>
#include <linux/slab.h>
#include <linux/device.h>
#define MEAS_LEN (8)
#define ACCURATE_BIT (12)
/* touch register */
#define MEAS_EN3 (0x52)
#define MEAS_TSIX_1 (0x8D)
#define MEAS_TSIX_2 (0x8E)
#define MEAS_TSIY_1 (0x8F)
#define MEAS_TSIY_2 (0x90)
#define MEAS_TSIZ1_1 (0x91)
#define MEAS_TSIZ1_2 (0x92)
#define MEAS_TSIZ2_1 (0x93)
#define MEAS_TSIZ2_2 (0x94)
/* bit definitions of touch */
#define MEAS_PD_EN (1 << 3)
#define MEAS_TSIX_EN (1 << 4)
#define MEAS_TSIY_EN (1 << 5)
#define MEAS_TSIZ1_EN (1 << 6)
#define MEAS_TSIZ2_EN (1 << 7)
struct pm860x_touch {
struct input_dev *idev;
struct i2c_client *i2c;
struct pm860x_chip *chip;
int irq;
int res_x; /* resistor of Xplate */
};
static irqreturn_t pm860x_touch_handler(int irq, void *data)
{
struct pm860x_touch *touch = data;
struct pm860x_chip *chip = touch->chip;
unsigned char buf[MEAS_LEN];
int x, y, pen_down;
int z1, z2, rt = 0;
int ret;
ret = pm860x_bulk_read(touch->i2c, MEAS_TSIX_1, MEAS_LEN, buf);
if (ret < 0)
goto out;
pen_down = buf[1] & (1 << 6);
x = ((buf[0] & 0xFF) << 4) | (buf[1] & 0x0F);
y = ((buf[2] & 0xFF) << 4) | (buf[3] & 0x0F);
z1 = ((buf[4] & 0xFF) << 4) | (buf[5] & 0x0F);
z2 = ((buf[6] & 0xFF) << 4) | (buf[7] & 0x0F);
if (pen_down) {
if ((x != 0) && (z1 != 0) && (touch->res_x != 0)) {
rt = z2 / z1 - 1;
rt = (rt * touch->res_x * x) >> ACCURATE_BIT;
dev_dbg(chip->dev, "z1:%d, z2:%d, rt:%d\n",
z1, z2, rt);
}
input_report_abs(touch->idev, ABS_X, x);
input_report_abs(touch->idev, ABS_Y, y);
input_report_abs(touch->idev, ABS_PRESSURE, rt);
input_report_key(touch->idev, BTN_TOUCH, 1);
dev_dbg(chip->dev, "pen down at [%d, %d].\n", x, y);
} else {
input_report_abs(touch->idev, ABS_PRESSURE, 0);
input_report_key(touch->idev, BTN_TOUCH, 0);
dev_dbg(chip->dev, "pen release\n");
}
input_sync(touch->idev);
out:
return IRQ_HANDLED;
}
static int pm860x_touch_open(struct input_dev *dev)
{
struct pm860x_touch *touch = input_get_drvdata(dev);
int data, ret;
data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN
| MEAS_TSIZ1_EN | MEAS_TSIZ2_EN;
ret = pm860x_set_bits(touch->i2c, MEAS_EN3, data, data);
if (ret < 0)
goto out;
return 0;
out:
return ret;
}
static void pm860x_touch_close(struct input_dev *dev)
{
struct pm860x_touch *touch = input_get_drvdata(dev);
int data;
data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN
| MEAS_TSIZ1_EN | MEAS_TSIZ2_EN;
pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0);
}
#ifdef CONFIG_OF
static int pm860x_touch_dt_init(struct platform_device *pdev,
struct pm860x_chip *chip,
int *res_x)
{
struct device_node *np = pdev->dev.parent->of_node;
struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
: chip->companion;
int data, n, ret;
if (!np)
return -ENODEV;
np = of_find_node_by_name(np, "touch");
if (!np) {
dev_err(&pdev->dev, "Can't find touch node\n");
return -EINVAL;
}
/* set GPADC MISC1 register */
data = 0;
if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-prebias", &n))
data |= (n << 1) & PM8607_GPADC_PREBIAS_MASK;
if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-slot-cycle", &n))
data |= (n << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-off-scale", &n))
data |= (n << 5) & PM8607_GPADC_OFF_SCALE_MASK;
if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-sw-cal", &n))
data |= (n << 7) & PM8607_GPADC_SW_CAL_MASK;
if (data) {
ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
if (ret < 0)
return -EINVAL;
}
/* set tsi prebias time */
if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) {
ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
if (ret < 0)
return -EINVAL;
}
/* set prebias & prechg time of pen detect */
data = 0;
if (!of_property_read_u32(np, "marvell,88pm860x-pen-prebias", &n))
data |= n & PM8607_PD_PREBIAS_MASK;
if (!of_property_read_u32(np, "marvell,88pm860x-pen-prechg", &n))
data |= n & PM8607_PD_PRECHG_MASK;
if (data) {
ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
if (ret < 0)
return -EINVAL;
}
of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x);
return 0;
}
#else
#define pm860x_touch_dt_init(x, y, z) (-1)
#endif
static int pm860x_touch_probe(struct platform_device *pdev)
{
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct pm860x_touch_pdata *pdata = dev_get_platdata(&pdev->dev);
struct pm860x_touch *touch;
struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
: chip->companion;
int irq, ret, res_x = 0, data = 0;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "No IRQ resource!\n");
return -EINVAL;
}
if (pm860x_touch_dt_init(pdev, chip, &res_x)) {
if (pdata) {
/* set GPADC MISC1 register */
data = 0;
data |= (pdata->gpadc_prebias << 1)
& PM8607_GPADC_PREBIAS_MASK;
data |= (pdata->slot_cycle << 3)
& PM8607_GPADC_SLOT_CYCLE_MASK;
data |= (pdata->off_scale << 5)
& PM8607_GPADC_OFF_SCALE_MASK;
data |= (pdata->sw_cal << 7)
& PM8607_GPADC_SW_CAL_MASK;
if (data) {
ret = pm860x_reg_write(i2c,
PM8607_GPADC_MISC1, data);
if (ret < 0)
return -EINVAL;
}
/* set tsi prebias time */
if (pdata->tsi_prebias) {
data = pdata->tsi_prebias;
ret = pm860x_reg_write(i2c,
PM8607_TSI_PREBIAS, data);
if (ret < 0)
return -EINVAL;
}
/* set prebias & prechg time of pen detect */
data = 0;
data |= pdata->pen_prebias
& PM8607_PD_PREBIAS_MASK;
data |= (pdata->pen_prechg << 5)
& PM8607_PD_PRECHG_MASK;
if (data) {
ret = pm860x_reg_write(i2c,
PM8607_PD_PREBIAS, data);
if (ret < 0)
return -EINVAL;
}
res_x = pdata->res_x;
} else {
dev_err(&pdev->dev, "failed to get platform data\n");
return -EINVAL;
}
}
/* enable GPADC */
ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1, PM8607_GPADC_EN,
PM8607_GPADC_EN);
if (ret)
return ret;
touch = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_touch),
GFP_KERNEL);
if (!touch)
return -ENOMEM;
platform_set_drvdata(pdev, touch);
touch->idev = devm_input_allocate_device(&pdev->dev);
if (!touch->idev) {
dev_err(&pdev->dev, "Failed to allocate input device!\n");
return -ENOMEM;
}
touch->idev->name = "88pm860x-touch";
touch->idev->phys = "88pm860x/input0";
touch->idev->id.bustype = BUS_I2C;
touch->idev->dev.parent = &pdev->dev;
touch->idev->open = pm860x_touch_open;
touch->idev->close = pm860x_touch_close;
touch->chip = chip;
touch->i2c = i2c;
touch->irq = irq;
touch->res_x = res_x;
input_set_drvdata(touch->idev, touch);
ret = devm_request_threaded_irq(&pdev->dev, touch->irq, NULL,
pm860x_touch_handler, IRQF_ONESHOT,
"touch", touch);
if (ret < 0)
return ret;
__set_bit(EV_ABS, touch->idev->evbit);
__set_bit(ABS_X, touch->idev->absbit);
__set_bit(ABS_Y, touch->idev->absbit);
__set_bit(ABS_PRESSURE, touch->idev->absbit);
__set_bit(EV_SYN, touch->idev->evbit);
__set_bit(EV_KEY, touch->idev->evbit);
__set_bit(BTN_TOUCH, touch->idev->keybit);
input_set_abs_params(touch->idev, ABS_X, 0, 1 << ACCURATE_BIT, 0, 0);
input_set_abs_params(touch->idev, ABS_Y, 0, 1 << ACCURATE_BIT, 0, 0);
input_set_abs_params(touch->idev, ABS_PRESSURE, 0, 1 << ACCURATE_BIT,
0, 0);
ret = input_register_device(touch->idev);
if (ret < 0) {
dev_err(chip->dev, "Failed to register touch!\n");
return ret;
}
platform_set_drvdata(pdev, touch);
return 0;
}
static struct platform_driver pm860x_touch_driver = {
.driver = {
.name = "88pm860x-touch",
.owner = THIS_MODULE,
},
.probe = pm860x_touch_probe,
};
module_platform_driver(pm860x_touch_driver);
MODULE_DESCRIPTION("Touchscreen driver for Marvell Semiconductor 88PM860x");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:88pm860x-touch");

View file

@ -0,0 +1,969 @@
#
# Touchscreen driver configuration
#
if INPUT_TOUCHSCREEN
config TOUCHSCREEN_88PM860X
tristate "Marvell 88PM860x touchscreen"
depends on MFD_88PM860X
help
Say Y here if you have a 88PM860x PMIC and want to enable
support for the built-in touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called 88pm860x-ts.
config TOUCHSCREEN_ADS7846
tristate "ADS7846/TSC2046/AD7873 and AD(S)7843 based touchscreens"
depends on SPI_MASTER
depends on HWMON = n || HWMON
help
Say Y here if you have a touchscreen interface using the
ADS7846/TSC2046/AD7873 or ADS7843/AD7843 controller,
and your board-specific setup code includes that in its
table of SPI devices.
If HWMON is selected, and the driver is told the reference voltage
on your board, you will also get hwmon interfaces for the voltage
(and on ads7846/tsc2046/ad7873, temperature) sensors of this chip.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ads7846.
config TOUCHSCREEN_AD7877
tristate "AD7877 based touchscreens"
depends on SPI_MASTER
help
Say Y here if you have a touchscreen interface using the
AD7877 controller, and your board-specific initialization
code includes that in its table of SPI devices.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7877.
config TOUCHSCREEN_AD7879
tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface"
help
Say Y here if you want to support a touchscreen interface using
the AD7879-1/AD7889-1 controller.
You should select a bus connection too.
To compile this driver as a module, choose M here: the
module will be called ad7879.
config TOUCHSCREEN_AD7879_I2C
tristate "support I2C bus connection"
depends on TOUCHSCREEN_AD7879 && I2C
help
Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called ad7879-i2c.
config TOUCHSCREEN_AD7879_SPI
tristate "support SPI bus connection"
depends on TOUCHSCREEN_AD7879 && SPI_MASTER
help
Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7879-spi.
config TOUCHSCREEN_ATMEL_MXT
tristate "Atmel mXT I2C Touchscreen"
depends on I2C
help
Say Y here if you have Atmel mXT series I2C touchscreen,
such as AT42QT602240/ATMXT224, connected to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called atmel_mxt_ts.
config TOUCHSCREEN_BITSY
tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
depends on SA1100_BITSY
select SERIO
help
Say Y here if you have the h3600 (Bitsy) touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called h3600_ts_input.
config TOUCHSCREEN_BU21013
tristate "BU21013 based touch panel controllers"
depends on I2C
help
Say Y here if you have a bu21013 touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called bu21013_ts.
config TOUCHSCREEN_CY8CTMG110
tristate "cy8ctmg110 touchscreen"
depends on I2C
depends on GPIOLIB
help
Say Y here if you have a cy8ctmg110 capacitive touchscreen on
an AAVA device.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cy8ctmg110_ts.
config TOUCHSCREEN_CYPRESS_CYTTSP5
tristate "Parade TrueTouch Gen5 Touchscreen Driver"
help
Core driver for Parade TrueTouch(tm) Standard Product
Geneartion5 touchscreen controllers.
Say Y here if you have a Parade Gen5 touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp5.
config TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
bool "Enable Device Tree support"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5 && OF
help
Say Y here to enable support for device tree.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG
bool "Enable debug output"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable debug output for Parade TrueTouch(tm)
Standard Product Generation5 drivers set.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_VDEBUG
bool "Enable verbose debug output"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG
help
Say Y here to enable verbose debug output for Parade TrueTouch(tm)
Standard Product Generation5 drivers set.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_I2C
tristate "Parade TrueTouch Gen5 I2C"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
select I2C
help
Say Y here to enable I2C bus interface to Parade TrueTouch(tm)
Standard Product Generation5 touchscreen controller.
If unsure, say Y.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_i2c.
config TOUCHSCREEN_CYPRESS_CYTTSP5_SPI
tristate "Parade TrueTouch Gen5 SPI"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
select SPI
help
Say Y here to enable SPI bus interface to Parade TrueTouch(tm)
Standard Product Generation5 touchscreen controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_spi.
choice
bool "Parade TrueTouch Gen5 MultiTouch Protocol"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
default TOUCHSCREEN_CYPRESS_CYTTSP5_MT_B
help
This option controls which MultiTouch protocol will be used to
report the touch events.
config TOUCHSCREEN_CYPRESS_CYTTSP5_MT_A
bool "Protocol A"
help
Select to enable MultiTouch touch reporting using protocol A
on Parade TrueTouch(tm) Standard Product Generation4 touchscreen
controller.
config TOUCHSCREEN_CYPRESS_CYTTSP5_MT_B
bool "Protocol B"
help
Select to enable MultiTouch touch reporting using protocol B
on Parade TrueTouch(tm) Standard Product Generation4 touchscreen
controller.
endchoice
config TOUCHSCREEN_CYPRESS_CYTTSP5_BUTTON
bool "Parade TrueTouch Gen5 MultiTouch CapSense Button"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable CapSense reporting on Parade TrueTouch(tm)
Standard Product Generation5 touchscreen controller.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_PROXIMITY
bool "Parade TrueTouch Gen5 Proximity"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable proximity reporting on Parade TrueTouch(tm)
Standard Product Generation5 touchscreen controller.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS
tristate "Parade TrueTouch Gen5 MultiTouch Device Access"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable Parade TrueTouch(tm) Standard Product
Generation5 touchscreen controller device access module.
This modules adds an interface to access touchscreen
controller using driver sysfs nodes.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_device_access.
config TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS_API
bool "Enable Device Access kernel API"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS
help
Say Y here to enable Device access kernel API which provides
access to Parade TrueTouch(tm) Standard Product Generation5
touchscreen controller for other modules.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_TEST_DEVICE_ACCESS_API
tristate "Simple Test module for Device Access kernel API"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS_API
help
Say Y here to enable test module for Device access kernel API.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_test_device_access_api.
config TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER
tristate "Parade TrueTouch Gen5 MultiTouch Loader"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable Parade TrueTouch(tm) Standard Product
Generation5 touchscreen controller FW Loader module.
This module enables support for Firmware upgrade.
If unsure, say Y.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_loader.
config TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
bool "FW upgrade from header file"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER
help
Say Y here to include Parade TrueTouch(tm) Standard Product
Generation5 device Firmware into driver.
Need proper header file for this.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
bool "FW upgrade from binary file"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER
help
Say Y here to include Parade TrueTouch(tm) Standard Product
Generation5 device Firmware into kernel as binary blob.
This should be enabled for manual FW upgrade support.
If unsure, say Y.
config TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE
bool "TT Configuration upgrade from header file"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER
help
Say Y here to include Parade TrueTouch(tm) Standard Product
Generation5 device TrueTouch Configuration into kernel itself.
Need proper header file for this.
If unsure, say N.
config TOUCHSCREEN_CYPRESS_CYTTSP5_MANUAL_TTCONFIG_UPGRADE
bool "TT Configuration upgrade via SysFs"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER
help
Say Y here to provide a SysFs interface to upgrade TrueTouch
Configuration with a binary configuration file.
Need proper binary version of config file for this
feature.
If unsure, say Y.
config TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG_MDL
tristate "Parade TrueTouch Gen5 MultiTouch Debug Module"
depends on TOUCHSCREEN_CYPRESS_CYTTSP5
help
Say Y here to enable Parade TrueTouch(tm) Standard Product
Generation5 Debug module.
This module adds support for verbose printing touch
information.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp5_debug.
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
default y
help
Say Y here to enable the support for the touchscreen found
on Dialog Semiconductor DA9034 PMIC.
config TOUCHSCREEN_DYNAPRO
tristate "Dynapro serial touchscreen"
select SERIO
help
Say Y here if you have a Dynapro serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called dynapro.
config TOUCHSCREEN_HAMPSHIRE
tristate "Hampshire serial touchscreen"
select SERIO
help
Say Y here if you have a Hampshire serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called hampshire.
config TOUCHSCREEN_EETI
tristate "EETI touchscreen panel support"
depends on I2C
help
Say Y here to enable support for I2C connected EETI touch panels.
To compile this driver as a module, choose M here: the
module will be called eeti_ts.
config TOUCHSCREEN_FUJITSU
tristate "Fujitsu serial touchscreen"
select SERIO
help
Say Y here if you have the Fujitsu touchscreen (such as one
installed in Lifebook P series laptop) connected to your
system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called fujitsu-ts.
config TOUCHSCREEN_S3C2410
tristate "Samsung S3C2410/generic touchscreen input driver"
depends on ARCH_S3C2410 || SAMSUNG_DEV_TS
select S3C_ADC
help
Say Y here if you have the s3c2410 touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called s3c2410_ts.
config TOUCHSCREEN_GUNZE
tristate "Gunze AHL-51S touchscreen"
select SERIO
help
Say Y here if you have the Gunze AHL-51 touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called gunze.
config TOUCHSCREEN_ELO
tristate "Elo serial touchscreens"
select SERIO
help
Say Y here if you have an Elo serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called elo.
config TOUCHSCREEN_WACOM_W8001
tristate "Wacom W8001 penabled serial touchscreen"
select SERIO
help
Say Y here if you have an Wacom W8001 penabled serial touchscreen
connected to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called wacom_w8001.
config TOUCHSCREEN_LPC32XX
tristate "LPC32XX touchscreen controller"
depends on ARCH_LPC32XX
help
Say Y here if you have a LPC32XX device and want
to support the built-in touchscreen.
To compile this driver as a module, choose M here: the
module will be called lpc32xx_ts.
config TOUCHSCREEN_MAX11801
tristate "MAX11801 based touchscreens"
depends on I2C
help
Say Y here if you have a MAX11801 based touchscreen
controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called max11801_ts.
config TOUCHSCREEN_MCS5000
tristate "MELFAS MCS-5000 touchscreen"
depends on I2C
help
Say Y here if you have the MELFAS MCS-5000 touchscreen controller
chip in your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mcs5000_ts.
config TOUCHSCREEN_MTOUCH
tristate "MicroTouch serial touchscreens"
select SERIO
help
Say Y here if you have a MicroTouch (3M) serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mtouch.
config TOUCHSCREEN_INEXIO
tristate "iNexio serial touchscreens"
select SERIO
help
Say Y here if you have an iNexio serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called inexio.
config TOUCHSCREEN_INTEL_MID
tristate "Intel MID platform resistive touchscreen"
depends on INTEL_SCU_IPC
help
Say Y here if you have a Intel MID based touchscreen in
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called intel_mid_touch.
config TOUCHSCREEN_MK712
tristate "ICS MicroClock MK712 touchscreen"
help
Say Y here if you have the ICS MicroClock MK712 touchscreen
controller chip in your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mk712.
config TOUCHSCREEN_HP600
tristate "HP Jornada 6xx touchscreen"
depends on SH_HP6XX && SH_ADC
help
Say Y here if you have a HP Jornada 620/660/680/690 and want to
support the built-in touchscreen.
To compile this driver as a module, choose M here: the
module will be called hp680_ts_input.
config TOUCHSCREEN_HP7XX
tristate "HP Jornada 7xx touchscreen"
depends on SA1100_JORNADA720_SSP
help
Say Y here if you have a HP Jornada 710/720/728 and want
to support the built-in touchscreen.
To compile this driver as a module, choose M here: the
module will be called jornada720_ts.
config TOUCHSCREEN_HTCPEN
tristate "HTC Shift X9500 touchscreen"
depends on ISA
help
Say Y here if you have an HTC Shift UMPC also known as HTC X9500
Clio / Shangrila and want to support the built-in touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called htcpen.
config TOUCHSCREEN_PENMOUNT
tristate "Penmount serial touchscreen"
select SERIO
help
Say Y here if you have a Penmount serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called penmount.
config TOUCHSCREEN_MIGOR
tristate "Renesas MIGO-R touchscreen"
depends on SH_MIGOR && I2C
help
Say Y here to enable MIGO-R touchscreen support.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called migor_ts.
config TOUCHSCREEN_TNETV107X
tristate "TI TNETV107X touchscreen support"
depends on ARCH_DAVINCI_TNETV107X
help
Say Y here if you want to use the TNETV107X touchscreen.
To compile this driver as a module, choose M here: the
module will be called tnetv107x-ts.
config TOUCHSCREEN_SYNAPTICS_I2C_RMI
tristate "Synaptics i2c touchscreen"
depends on I2C
help
This enables support for Synaptics RMI over I2C based touchscreens.
config TOUCHSCREEN_TOUCHRIGHT
tristate "Touchright serial touchscreen"
select SERIO
help
Say Y here if you have a Touchright serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called touchright.
config TOUCHSCREEN_TOUCHWIN
tristate "Touchwin serial touchscreen"
select SERIO
help
Say Y here if you have a Touchwin serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called touchwin.
config TOUCHSCREEN_ATMEL_TSADCC
tristate "Atmel Touchscreen Interface"
depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
help
Say Y here if you have a 4-wire touchscreen connected to the
ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called atmel_tsadcc.
config TOUCHSCREEN_UCB1400
tristate "Philips UCB1400 touchscreen"
depends on AC97_BUS
depends on UCB1400_CORE
help
This enables support for the Philips UCB1400 touchscreen interface.
The UCB1400 is an AC97 audio codec. The touchscreen interface
will be initialized only after the ALSA subsystem has been
brought up and the UCB1400 detected. You therefore have to
configure ALSA support as well (either built-in or modular,
independently of whether this driver is itself built-in or
modular) for this driver to work.
To compile this driver as a module, choose M here: the
module will be called ucb1400_ts.
config TOUCHSCREEN_WM831X
tristate "Support for WM831x touchscreen controllers"
depends on MFD_WM831X
help
This enables support for the touchscreen controller on the WM831x
series of PMICs.
To compile this driver as a module, choose M here: the
module will be called wm831x-ts.
config TOUCHSCREEN_WM97XX
tristate "Support for WM97xx AC97 touchscreen controllers"
depends on AC97_BUS
help
Say Y here if you have a Wolfson Microelectronics WM97xx
touchscreen connected to your system. Note that this option
only enables core driver, you will also need to select
support for appropriate chip below.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called wm97xx-ts.
config TOUCHSCREEN_WM9705
bool "WM9705 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
default y
help
Say Y here to enable support for the Wolfson Microelectronics
WM9705 touchscreen controller.
config TOUCHSCREEN_WM9712
bool "WM9712 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
default y
help
Say Y here to enable support for the Wolfson Microelectronics
WM9712 touchscreen controller.
config TOUCHSCREEN_WM9713
bool "WM9713 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
default y
help
Say Y here to enable support for the Wolfson Microelectronics
WM9713 touchscreen controller.
config TOUCHSCREEN_WM97XX_ATMEL
tristate "WM97xx Atmel accelerated touch"
depends on TOUCHSCREEN_WM97XX && (AVR32 || ARCH_AT91)
help
Say Y here for support for streaming mode with WM97xx touchscreens
on Atmel AT91 or AVR32 systems with an AC97C module.
Be aware that this will use channel B in the controller for
streaming data, this must not conflict with other AC97C drivers.
If unsure, say N.
To compile this driver as a module, choose M here: the module will
be called atmel-wm97xx.
config TOUCHSCREEN_WM97XX_MAINSTONE
tristate "WM97xx Mainstone/Palm accelerated touch"
depends on TOUCHSCREEN_WM97XX && ARCH_PXA
help
Say Y here for support for streaming mode with WM97xx touchscreens
on Mainstone, Palm Tungsten T5, TX and LifeDrive systems.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mainstone-wm97xx.
config TOUCHSCREEN_WM97XX_ZYLONITE
tristate "Zylonite accelerated touch"
depends on TOUCHSCREEN_WM97XX && MACH_ZYLONITE
select TOUCHSCREEN_WM9713
help
Say Y here for support for streaming mode with the touchscreen
on Zylonite systems.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called zylonite-wm97xx.
config TOUCHSCREEN_USB_COMPOSITE
tristate "USB Touchscreen Driver"
depends on USB_ARCH_HAS_HCD
select USB
help
USB Touchscreen driver for:
- eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
- PanJit TouchSet USB
- 3M MicroTouch USB (EX II series)
- ITM
- some other eTurboTouch
- Gunze AHL61
- DMC TSC-10/25
- IRTOUCHSYSTEMS/UNITOP
- IdealTEK URTC1000
- GoTop Super_Q2/GogoPen/PenPower tablets
- JASTEC USB Touch Controller/DigiTech DTR-02U
- Zytronic controllers
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
To compile this driver as a module, choose M here: the
module will be called usbtouchscreen.
config TOUCHSCREEN_MC13783
tristate "Freescale MC13783 touchscreen input driver"
depends on MFD_MC13783
help
Say Y here if you have an Freescale MC13783 PMIC on your
board and want to use its touchscreen
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mc13783_ts.
config TOUCHSCREEN_USB_EGALAX
default y
bool "eGalax, eTurboTouch CT-410/510/700 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_PANJIT
default y
bool "PanJit device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_3M
default y
bool "3M/Microtouch EX II series device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ITM
default y
bool "ITM device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ETURBO
default y
bool "eTurboTouch (non-eGalax compatible) device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GUNZE
default y
bool "Gunze AHL61 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_DMC_TSC10
default y
bool "DMC TSC-10/25 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_IRTOUCH
default y
bool "IRTOUCHSYSTEMS/UNITOP device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_IDEALTEK
default y
bool "IdealTEK URTC1000 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GENERAL_TOUCH
default y
bool "GeneralTouch Touchscreen device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GOTOP
default y
bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_JASTEC
default y
bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_E2I
default y
bool "e2i Touchscreen controller (e.g. from Mimo 740)"
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ZYTRONIC
default y
bool "Zytronic controller" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ETT_TC45USB
default y
bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_NEXIO
default y
bool "NEXIO/iNexio device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_TOUCHIT213
tristate "Sahara TouchIT-213 touchscreen"
select SERIO
help
Say Y here if you have a Sahara TouchIT-213 Tablet PC.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called touchit213.
config TOUCHSCREEN_TSC_SERIO
tristate "TSC-10/25/40 serial touchscreen support"
select SERIO
help
Say Y here if you have a TSC-10, 25 or 40 serial touchscreen connected
to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tsc40.
config TOUCHSCREEN_TSC2005
tristate "TSC2005 based touchscreens"
depends on SPI_MASTER && GENERIC_HARDIRQS
help
Say Y here if you have a TSC2005 based touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tsc2005.
config TOUCHSCREEN_TSC2007
tristate "TSC2007 based touchscreens"
depends on I2C
help
Say Y here if you have a TSC2007 based touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tsc2007.
config TOUCHSCREEN_W90X900
tristate "W90P910 touchscreen driver"
depends on HAVE_CLK
help
Say Y here if you have a W90P910 based touchscreen.
To compile this driver as a module, choose M here: the
module will be called w90p910_ts.
config TOUCHSCREEN_PCAP
tristate "Motorola PCAP touchscreen"
depends on EZX_PCAP
help
Say Y here if you have a Motorola EZX telephone and
want to enable support for the built-in touchscreen.
To compile this driver as a module, choose M here: the
module will be called pcap_ts.
config TOUCHSCREEN_ST1232
tristate "Sitronix ST1232 touchscreen controllers"
depends on I2C
help
Say Y here if you want to support Sitronix ST1232
touchscreen controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called st1232_ts.
config TOUCHSCREEN_STMPE
tristate "STMicroelectronics STMPE touchscreens"
depends on MFD_STMPE
help
Say Y here if you want support for STMicroelectronics
STMPE touchscreen controllers.
To compile this driver as a module, choose M here: the
module will be called stmpe-ts.
config TOUCHSCREEN_TPS6507X
tristate "TPS6507x based touchscreens"
depends on I2C
help
Say Y here if you have a TPS6507x based touchscreen
controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tps6507x_ts.
config TOUCHSCREEN_SYNTM12XX
tristate "Synaptic TM12xx touchscreen"
depends on I2C
help
Say Y here to enable support for Synaptic TM12xx
series touchscreen controller.
If unsure, say N.
To compile this driver as module, choose M here: the
module will be called syntm12xx
endif

View file

@ -0,0 +1,113 @@
#
# Makefile for the touchscreen drivers.
#
# Each configuration option enables a list of files.
wm97xx-ts-y := wm97xx-core.o
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI) += synaptics_i2c_rmi.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
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_TOUCHSCREEN_SYNTM12XX) += syntm12xx.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5) += cyttsp5.o
cyttsp5-y := cyttsp5_core.o cyttsp5_mt_common.o
cyttsp5-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MT_A) += cyttsp5_mta.o
cyttsp5-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MT_B) += cyttsp5_mtb.o
cyttsp5-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BUTTON) += cyttsp5_btn.o
cyttsp5-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PROXIMITY) += cyttsp5_proximity.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT) += cyttsp5_devtree.o
ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5
obj-y += cyttsp5_platform.o
endif
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_I2C) += cyttsp5_i2c.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_SPI) += cyttsp5_spi.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG_MDL) += cyttsp5_debug.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_LOADER) += cyttsp5_loader.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS) += cyttsp5_device_access.o
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_TEST_DEVICE_ACCESS_API) += cyttsp5_test_device_access_api.o
ifeq ($(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEBUG),y)
CFLAGS_cyttsp5_core.o += -DDEBUG
CFLAGS_cyttsp5_i2c.o += -DDEBUG
CFLAGS_cyttsp5_spi.o += -DDEBUG
CFLAGS_cyttsp5_mta.o += -DDEBUG
CFLAGS_cyttsp5_mtb.o += -DDEBUG
CFLAGS_cyttsp5_mt_common.o += -DDEBUG
CFLAGS_cyttsp5_btn.o += -DDEBUG
CFLAGS_cyttsp5_proximity.o += -DDEBUG
CFLAGS_cyttsp5_device_access.o += -DDEBUG
CFLAGS_cyttsp5_loader.o += -DDEBUG
CFLAGS_cyttsp5_debug.o += -DDEBUG
CFLAGS_cyttsp5_devtree.o += -DDEBUG
CFLAGS_cyttsp5_platform.o += -DDEBUG
endif
ifeq ($(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_VDEBUG),y)
CFLAGS_cyttsp5_core.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_i2c.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_spi.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_mta.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_mtb.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_mt_common.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_btn.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_proximity.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_device_access.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_loader.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_debug.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_devtree.o += -DVERBOSE_DEBUG
CFLAGS_cyttsp5_platform.o += -DVERBOSE_DEBUG
endif

View file

@ -0,0 +1,367 @@
/*
* cyttsp5_btn.c
* Parade TrueTouch(TM) Standard Product V5 CapSense Reports Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#define CYTTSP5_BTN_NAME "cyttsp5_btn"
static inline void cyttsp5_btn_key_action(struct cyttsp5_btn_data *bd,
int btn_no, int btn_state)
{
struct device *dev = bd->dev;
struct cyttsp5_sysinfo *si = bd->si;
if (!si->btn[btn_no].enabled ||
si->btn[btn_no].state == btn_state)
return;
si->btn[btn_no].state = btn_state;
input_report_key(bd->input, si->btn[btn_no].key_code, btn_state);
input_sync(bd->input);
dev_dbg(dev, "%s: btn=%d key_code=%d %s\n", __func__,
btn_no, si->btn[btn_no].key_code,
btn_state == CY_BTN_PRESSED ?
"PRESSED" : "RELEASED");
}
static void cyttsp5_get_btn_touches(struct cyttsp5_btn_data *bd)
{
struct cyttsp5_sysinfo *si = bd->si;
int num_btns = si->num_btns;
int cur_btn;
int cur_btn_state;
for (cur_btn = 0; cur_btn < num_btns; cur_btn++) {
/* Get current button state */
cur_btn_state = (si->xy_data[0] >> (cur_btn * CY_BITS_PER_BTN))
& CY_NUM_BTN_EVENT_ID;
cyttsp5_btn_key_action(bd, cur_btn, cur_btn_state);
}
}
static void cyttsp5_btn_lift_all(struct cyttsp5_btn_data *bd)
{
struct cyttsp5_sysinfo *si = bd->si;
int i;
if (!si || si->num_btns == 0)
return;
for (i = 0; i < si->num_btns; i++)
cyttsp5_btn_key_action(bd, i, CY_BTN_RELEASED);
}
#ifdef VERBOSE_DEBUG
static void cyttsp5_log_btn_data(struct cyttsp5_btn_data *bd)
{
struct device *dev = bd->dev;
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
u8 *pr_buf = cd->pr_buf;
struct cyttsp5_sysinfo *si = bd->si;
int cur;
int value;
for (cur = 0; cur < si->num_btns; cur++) {
pr_buf[0] = 0;
if (si->xy_data[0] & (1 << cur))
value = 1;
else
value = 0;
snprintf(pr_buf, CY_MAX_PRBUF_SIZE, "btn_rec[%d]=0x", cur);
snprintf(pr_buf, CY_MAX_PRBUF_SIZE, "%s%X (%02X)",
pr_buf, value,
le16_to_cpu(si->xy_data[1 + cur * 2]));
dev_vdbg(dev, "%s: %s\n", __func__, pr_buf);
}
}
#endif
/* read xy_data for all current CapSense button touches */
static int cyttsp5_xy_worker(struct cyttsp5_btn_data *bd)
{
struct cyttsp5_sysinfo *si = bd->si;
/* extract button press/release touch information */
if (si->num_btns > 0) {
cyttsp5_get_btn_touches(bd);
#ifdef VERBOSE_DEBUG
/* log button press/release touch information */
cyttsp5_log_btn_data(bd);
#endif
}
return 0;
}
static int cyttsp5_btn_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
int rc;
if (bd->si->xy_mode[2] != bd->si->desc.btn_report_id)
return 0;
/* core handles handshake */
mutex_lock(&bd->btn_lock);
rc = cyttsp5_xy_worker(bd);
mutex_unlock(&bd->btn_lock);
if (rc < 0)
dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
return rc;
}
static int cyttsp5_startup_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
mutex_lock(&bd->btn_lock);
cyttsp5_btn_lift_all(bd);
mutex_unlock(&bd->btn_lock);
return 0;
}
static int cyttsp5_btn_suspend_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
mutex_lock(&bd->btn_lock);
cyttsp5_btn_lift_all(bd);
bd->is_suspended = true;
mutex_unlock(&bd->btn_lock);
pm_runtime_put(dev);
return 0;
}
static int cyttsp5_btn_resume_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
pm_runtime_get(dev);
mutex_lock(&bd->btn_lock);
bd->is_suspended = false;
mutex_unlock(&bd->btn_lock);
return 0;
}
static int cyttsp5_btn_open(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
pm_runtime_get_sync(dev);
mutex_lock(&bd->btn_lock);
bd->is_suspended = false;
mutex_unlock(&bd->btn_lock);
dev_vdbg(dev, "%s: setup subscriptions\n", __func__);
/* set up touch call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_BTN_NAME,
cyttsp5_btn_attention, CY_MODE_OPERATIONAL);
/* set up startup call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_BTN_NAME,
cyttsp5_startup_attention, 0);
/* set up suspend call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_SUSPEND, CYTTSP5_BTN_NAME,
cyttsp5_btn_suspend_attention, 0);
/* set up resume call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_RESUME, CYTTSP5_BTN_NAME,
cyttsp5_btn_resume_attention, 0);
return 0;
}
static void cyttsp5_btn_close(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_BTN_NAME,
cyttsp5_btn_attention, CY_MODE_OPERATIONAL);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_BTN_NAME,
cyttsp5_startup_attention, 0);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_SUSPEND, CYTTSP5_BTN_NAME,
cyttsp5_btn_suspend_attention, 0);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_RESUME, CYTTSP5_BTN_NAME,
cyttsp5_btn_resume_attention, 0);
mutex_lock(&bd->btn_lock);
if (!bd->is_suspended) {
pm_runtime_put(dev);
bd->is_suspended = true;
}
mutex_unlock(&bd->btn_lock);
}
static int cyttsp5_setup_input_device(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
int i;
int rc;
dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
__set_bit(EV_KEY, bd->input->evbit);
dev_vdbg(dev, "%s: Number of buttons %d\n", __func__, bd->si->num_btns);
for (i = 0; i < bd->si->num_btns; i++) {
dev_vdbg(dev, "%s: btn:%d keycode:%d\n",
__func__, i, bd->si->btn[i].key_code);
__set_bit(bd->si->btn[i].key_code, bd->input->keybit);
}
rc = input_register_device(bd->input);
if (rc < 0)
dev_err(dev, "%s: Error, failed register input device r=%d\n",
__func__, rc);
else
bd->input_device_registered = true;
return rc;
}
static int cyttsp5_setup_input_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
int rc;
bd->si = _cyttsp5_request_sysinfo(dev);
if (!bd->si)
return -1;
rc = cyttsp5_setup_input_device(dev);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_BTN_NAME,
cyttsp5_setup_input_attention, 0);
return rc;
}
int cyttsp5_btn_probe(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
struct cyttsp5_btn_platform_data *btn_pdata;
int rc = 0;
if (!pdata || !pdata->btn_pdata) {
dev_err(dev, "%s: Missing platform data\n", __func__);
rc = -ENODEV;
goto error_no_pdata;
}
btn_pdata = pdata->btn_pdata;
mutex_init(&bd->btn_lock);
bd->dev = dev;
bd->pdata = btn_pdata;
/* Create the input device and register it. */
dev_vdbg(dev, "%s: Create the input device and register it\n",
__func__);
bd->input = input_allocate_device();
if (!bd->input) {
dev_err(dev, "%s: Error, failed to allocate input device\n",
__func__);
rc = -ENODEV;
goto error_alloc_failed;
}
if (bd->pdata->inp_dev_name)
bd->input->name = bd->pdata->inp_dev_name;
else
bd->input->name = CYTTSP5_BTN_NAME;
scnprintf(bd->phys, sizeof(bd->phys), "%s/input%d", dev_name(dev),
cd->phys_num++);
bd->input->phys = bd->phys;
bd->input->dev.parent = bd->dev;
bd->input->open = cyttsp5_btn_open;
bd->input->close = cyttsp5_btn_close;
input_set_drvdata(bd->input, bd);
/* get sysinfo */
bd->si = _cyttsp5_request_sysinfo(dev);
if (bd->si) {
rc = cyttsp5_setup_input_device(dev);
if (rc)
goto error_init_input;
} else {
dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
__func__, bd->si);
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_BTN_NAME, cyttsp5_setup_input_attention, 0);
}
return 0;
error_init_input:
input_free_device(bd->input);
error_alloc_failed:
error_no_pdata:
dev_err(dev, "%s failed.\n", __func__);
return rc;
}
int cyttsp5_btn_release(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_btn_data *bd = &cd->bd;
if (bd->input_device_registered) {
input_unregister_device(bd->input);
} else {
input_free_device(bd->input);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_BTN_NAME, cyttsp5_setup_input_attention, 0);
}
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,393 @@
/*
* cyttsp5_debug.c
* Parade TrueTouch(TM) Standard Product V5 Debug Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#define CYTTSP5_DEBUG_NAME "cyttsp5_debug"
struct cyttsp5_debug_data {
struct device *dev;
struct cyttsp5_sysinfo *si;
uint32_t interrupt_count;
uint32_t formated_output;
struct mutex sysfs_lock;
u8 pr_buf[CY_MAX_PRBUF_SIZE];
};
static struct cyttsp5_core_commands *cmd;
static struct cyttsp5_module debug_module;
static inline struct cyttsp5_debug_data *cyttsp5_get_debug_data(
struct device *dev)
{
return cyttsp5_get_module_data(dev, &debug_module);
}
/*
* This function provide output of combined xy_mode and xy_data.
* Required by TTHE.
*/
static void cyttsp5_pr_buf_op_mode(struct cyttsp5_debug_data *dd, u8 *pr_buf,
struct cyttsp5_sysinfo *si, u8 cur_touch)
{
const char fmt[] = "%02X ";
int max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED);
u8 report_id = si->xy_mode[2];
int header_size = 0;
int report_size = 0;
int total_size = 0;
int i, k;
if (report_id == si->desc.tch_report_id) {
header_size = si->desc.tch_header_size;
report_size = cur_touch * si->desc.tch_record_size;
} else if (report_id == si->desc.btn_report_id) {
header_size = BTN_INPUT_HEADER_SIZE;
report_size = BTN_REPORT_SIZE;
}
total_size = header_size + report_size;
pr_buf[0] = 0;
for (i = k = 0; i < header_size && i < max; i++, k += 3)
scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, si->xy_mode[i]);
for (i = 0; i < report_size && i < max; i++, k += 3)
scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, si->xy_data[i]);
pr_info("%s=%s%s\n", "cyttsp5_OpModeData", pr_buf,
total_size <= max ? "" : CY_PR_TRUNCATED);
}
static void cyttsp5_debug_print(struct device *dev, u8 *pr_buf, u8 *sptr,
int size, const char *data_name)
{
int i, j;
int elem_size = sizeof("XX ") - 1;
int max = (CY_MAX_PRBUF_SIZE - 1) / elem_size;
int limit = size < max ? size : max;
if (limit < 0)
limit = 0;
pr_buf[0] = 0;
for (i = j = 0; i < limit; i++, j += elem_size)
scnprintf(pr_buf + j, CY_MAX_PRBUF_SIZE - j, "%02X ", sptr[i]);
if (size)
pr_info("%s[0..%d]=%s%s\n", data_name, size - 1, pr_buf,
size <= max ? "" : CY_PR_TRUNCATED);
else
pr_info("%s[]\n", data_name);
}
static void cyttsp5_debug_formated(struct device *dev, u8 *pr_buf,
struct cyttsp5_sysinfo *si, u8 num_cur_tch)
{
u8 report_id = si->xy_mode[2];
int header_size = 0;
int report_size = 0;
u8 data_name[] = "touch[99]";
int max_print_length = 20;
int i;
if (report_id == si->desc.tch_report_id) {
header_size = si->desc.tch_header_size;
report_size = num_cur_tch * si->desc.tch_record_size;
} else if (report_id == si->desc.btn_report_id) {
header_size = BTN_INPUT_HEADER_SIZE;
report_size = BTN_REPORT_SIZE;
}
/* xy_mode */
cyttsp5_debug_print(dev, pr_buf, si->xy_mode, header_size, "xy_mode");
/* xy_data */
if (report_size > max_print_length) {
pr_info("xy_data[0..%d]:\n", report_size);
for (i = 0; i < report_size - max_print_length;
i += max_print_length) {
cyttsp5_debug_print(dev, pr_buf, si->xy_data + i,
max_print_length, " ");
}
if (report_size - i)
cyttsp5_debug_print(dev, pr_buf, si->xy_data + i,
report_size - i, " ");
} else {
cyttsp5_debug_print(dev, pr_buf, si->xy_data, report_size,
"xy_data");
}
/* touches */
if (report_id == si->desc.tch_report_id) {
for (i = 0; i < num_cur_tch; i++) {
scnprintf(data_name, sizeof(data_name) - 1,
"touch[%u]", i);
cyttsp5_debug_print(dev, pr_buf,
si->xy_data + (i * si->desc.tch_record_size),
si->desc.tch_record_size, data_name);
}
}
/* buttons */
if (report_id == si->desc.btn_report_id)
cyttsp5_debug_print(dev, pr_buf, si->xy_data, report_size,
"button");
}
/* read xy_data for all touches for debug */
static int cyttsp5_xy_worker(struct cyttsp5_debug_data *dd)
{
struct device *dev = dd->dev;
struct cyttsp5_sysinfo *si = dd->si;
u8 report_reg = si->xy_mode[TOUCH_COUNT_BYTE_OFFSET];
u8 num_cur_tch = GET_NUM_TOUCHES(report_reg);
uint32_t formated_output;
mutex_lock(&dd->sysfs_lock);
dd->interrupt_count++;
formated_output = dd->formated_output;
mutex_unlock(&dd->sysfs_lock);
/* Interrupt */
pr_info("Interrupt(%u)\n", dd->interrupt_count);
if (formated_output)
cyttsp5_debug_formated(dev, dd->pr_buf, si, num_cur_tch);
else
/* print data for TTHE */
cyttsp5_pr_buf_op_mode(dd, dd->pr_buf, si, num_cur_tch);
pr_info("\n");
return 0;
}
static int cyttsp5_debug_attention(struct device *dev)
{
struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
struct cyttsp5_sysinfo *si = dd->si;
u8 report_id = si->xy_mode[2];
int rc = 0;
if (report_id != si->desc.tch_report_id
&& report_id != si->desc.btn_report_id)
return 0;
/* core handles handshake */
rc = cyttsp5_xy_worker(dd);
if (rc < 0)
dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
return rc;
}
static ssize_t cyttsp5_interrupt_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
int val;
mutex_lock(&dd->sysfs_lock);
val = dd->interrupt_count;
mutex_unlock(&dd->sysfs_lock);
return scnprintf(buf, CY_MAX_PRBUF_SIZE, "Interrupt Count: %d\n", val);
}
static ssize_t cyttsp5_interrupt_count_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
mutex_lock(&dd->sysfs_lock);
dd->interrupt_count = 0;
mutex_unlock(&dd->sysfs_lock);
return size;
}
static DEVICE_ATTR(int_count, S_IRUSR | S_IWUSR,
cyttsp5_interrupt_count_show, cyttsp5_interrupt_count_store);
static ssize_t cyttsp5_formated_output_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
int val;
mutex_lock(&dd->sysfs_lock);
val = dd->formated_output;
mutex_unlock(&dd->sysfs_lock);
return scnprintf(buf, CY_MAX_PRBUF_SIZE,
"Formated debug output: %x\n", val);
}
static ssize_t cyttsp5_formated_output_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
unsigned long value;
int rc;
rc = kstrtoul(buf, 10, &value);
if (rc < 0) {
dev_err(dev, "%s: Invalid value\n", __func__);
return size;
}
/* Expecting only 0 or 1 */
if (value != 0 && value != 1) {
dev_err(dev, "%s: Invalid value %lu\n", __func__, value);
return size;
}
mutex_lock(&dd->sysfs_lock);
dd->formated_output = value;
mutex_unlock(&dd->sysfs_lock);
return size;
}
static DEVICE_ATTR(formated_output, S_IRUSR | S_IWUSR,
cyttsp5_formated_output_show, cyttsp5_formated_output_store);
static int cyttsp5_debug_probe(struct device *dev, void **data)
{
struct cyttsp5_debug_data *dd;
int rc;
/* get context and debug print buffers */
dd = kzalloc(sizeof(*dd), GFP_KERNEL);
if (!dd) {
rc = -ENOMEM;
goto cyttsp5_debug_probe_alloc_failed;
}
rc = device_create_file(dev, &dev_attr_int_count);
if (rc) {
dev_err(dev, "%s: Error, could not create int_count\n",
__func__);
goto cyttsp5_debug_probe_create_int_count_failed;
}
rc = device_create_file(dev, &dev_attr_formated_output);
if (rc) {
dev_err(dev, "%s: Error, could not create formated_output\n",
__func__);
goto cyttsp5_debug_probe_create_formated_failed;
}
mutex_init(&dd->sysfs_lock);
dd->dev = dev;
*data = dd;
dd->si = cmd->request_sysinfo(dev);
if (!dd->si) {
dev_err(dev, "%s: Fail get sysinfo pointer from core\n",
__func__);
rc = -ENODEV;
goto cyttsp5_debug_probe_sysinfo_failed;
}
rc = cmd->subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_DEBUG_NAME,
cyttsp5_debug_attention, CY_MODE_OPERATIONAL);
if (rc < 0) {
dev_err(dev, "%s: Error, could not subscribe attention cb\n",
__func__);
goto cyttsp5_debug_probe_subscribe_failed;
}
return 0;
cyttsp5_debug_probe_subscribe_failed:
cyttsp5_debug_probe_sysinfo_failed:
device_remove_file(dev, &dev_attr_formated_output);
cyttsp5_debug_probe_create_formated_failed:
device_remove_file(dev, &dev_attr_int_count);
cyttsp5_debug_probe_create_int_count_failed:
kfree(dd);
cyttsp5_debug_probe_alloc_failed:
dev_err(dev, "%s failed.\n", __func__);
return rc;
}
static void cyttsp5_debug_release(struct device *dev, void *data)
{
struct cyttsp5_debug_data *dd = data;
int rc;
rc = cmd->unsubscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_DEBUG_NAME,
cyttsp5_debug_attention, CY_MODE_OPERATIONAL);
if (rc < 0) {
dev_err(dev, "%s: Error, could not un-subscribe attention\n",
__func__);
goto cyttsp5_debug_release_exit;
}
cyttsp5_debug_release_exit:
device_remove_file(dev, &dev_attr_formated_output);
device_remove_file(dev, &dev_attr_int_count);
kfree(dd);
}
static struct cyttsp5_module debug_module = {
.name = CYTTSP5_DEBUG_NAME,
.probe = cyttsp5_debug_probe,
.release = cyttsp5_debug_release,
};
static int __init cyttsp5_debug_init(void)
{
int rc;
cmd = cyttsp5_get_commands();
if (!cmd)
return -EINVAL;
rc = cyttsp5_register_module(&debug_module);
if (rc < 0) {
pr_err("%s: Error, failed registering module\n",
__func__);
return rc;
}
pr_info("%s: Parade TTSP Debug Driver (Built %s) rc=%d\n",
__func__, CY_DRIVER_VERSION, rc);
return 0;
}
module_init(cyttsp5_debug_init);
static void __exit cyttsp5_debug_exit(void)
{
cyttsp5_unregister_module(&debug_module);
}
module_exit(cyttsp5_debug_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Debug Driver");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,747 @@
/*
* cyttsp5_devtree.c
* Parade TrueTouch(TM) Standard Product V5 Device Tree Support Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2013-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of_device.h>
#include <linux/slab.h>
/* cyttsp */
#include "cyttsp5_regs.h"
#include <linux/cyttsp5_platform.h>
#define ENABLE_VIRTUAL_KEYS
#define MAX_NAME_LENGTH 64
enum cyttsp5_device_type {
DEVICE_MT,
DEVICE_BTN,
DEVICE_PROXIMITY,
DEVICE_TYPE_MAX,
};
struct cyttsp5_device_pdata_func {
void * (*create_and_get_pdata)(struct device_node *);
void (*free_pdata)(void *);
};
struct cyttsp5_pdata_ptr {
void **pdata;
};
#ifdef ENABLE_VIRTUAL_KEYS
static struct kobject *board_properties_kobj;
struct cyttsp5_virtual_keys {
struct kobj_attribute kobj_attr;
u16 *data;
int size;
};
#endif
struct cyttsp5_extended_mt_platform_data {
struct cyttsp5_mt_platform_data pdata;
#ifdef ENABLE_VIRTUAL_KEYS
struct cyttsp5_virtual_keys vkeys;
#endif
};
static inline int get_inp_dev_name(struct device_node *dev_node,
const char **inp_dev_name)
{
return of_property_read_string(dev_node, "cy,inp_dev_name",
inp_dev_name);
}
static s16 *create_and_get_u16_array(struct device_node *dev_node,
const char *name, int *size)
{
const __be32 *values;
s16 *val_array;
int len;
int sz;
int rc;
int i;
values = of_get_property(dev_node, name, &len);
if (values == NULL)
return NULL;
sz = len / sizeof(u32);
pr_debug("%s: %s size:%d\n", __func__, name, sz);
val_array = kcalloc(sz, sizeof(s16), GFP_KERNEL);
if (!val_array) {
rc = -ENOMEM;
goto fail;
}
for (i = 0; i < sz; i++)
val_array[i] = (s16)be32_to_cpup(values++);
*size = sz;
return val_array;
fail:
return ERR_PTR(rc);
}
static struct touch_framework *create_and_get_touch_framework(
struct device_node *dev_node)
{
struct touch_framework *frmwrk;
s16 *abs;
int size;
int rc;
abs = create_and_get_u16_array(dev_node, "cy,abs", &size);
if (IS_ERR_OR_NULL(abs))
return (void *)abs;
/* Check for valid abs size */
if (size % CY_NUM_ABS_SET) {
rc = -EINVAL;
goto fail_free_abs;
}
frmwrk = kzalloc(sizeof(*frmwrk), GFP_KERNEL);
if (!frmwrk) {
rc = -ENOMEM;
goto fail_free_abs;
}
frmwrk->abs = abs;
frmwrk->size = size;
return frmwrk;
fail_free_abs:
kfree(abs);
return ERR_PTR(rc);
}
static void free_touch_framework(struct touch_framework *frmwrk)
{
kfree(frmwrk->abs);
kfree(frmwrk);
}
#ifdef ENABLE_VIRTUAL_KEYS
#define VIRTUAL_KEY_ELEMENT_SIZE 5
static ssize_t virtual_keys_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct cyttsp5_virtual_keys *vkeys = container_of(attr,
struct cyttsp5_virtual_keys, kobj_attr);
u16 *data = vkeys->data;
int size = vkeys->size;
int index;
int i;
index = 0;
for (i = 0; i < size; i += VIRTUAL_KEY_ELEMENT_SIZE)
index += scnprintf(buf + index, CY_MAX_PRBUF_SIZE - index,
"0x01:%d:%d:%d:%d:%d\n",
data[i], data[i+1], data[i+2], data[i+3], data[i+4]);
return index;
}
static int setup_virtual_keys(struct device_node *dev_node,
const char *inp_dev_name, struct cyttsp5_virtual_keys *vkeys)
{
char *name;
u16 *data;
int size;
int rc;
data = create_and_get_u16_array(dev_node, "cy,virtual_keys", &size);
if (data == NULL)
return 0;
else if (IS_ERR(data)) {
rc = PTR_ERR(data);
goto fail;
}
/* Check for valid virtual keys size */
if (size % VIRTUAL_KEY_ELEMENT_SIZE) {
rc = -EINVAL;
goto fail_free_data;
}
name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL);
if (!name) {
rc = -ENOMEM;
goto fail_free_data;
}
snprintf(name, MAX_NAME_LENGTH, "virtualkeys.%s", inp_dev_name);
vkeys->data = data;
vkeys->size = size;
/* TODO: Instantiate in board file and export it */
if (board_properties_kobj == NULL)
board_properties_kobj =
kobject_create_and_add("board_properties", NULL);
if (board_properties_kobj == NULL) {
pr_err("%s: Cannot get board_properties kobject!\n", __func__);
rc = -EINVAL;
goto fail_free_name;
}
/* Initialize dynamic SysFs attribute */
sysfs_attr_init(&vkeys->kobj_attr.attr);
vkeys->kobj_attr.attr.name = name;
vkeys->kobj_attr.attr.mode = S_IRUGO;
vkeys->kobj_attr.show = virtual_keys_show;
rc = sysfs_create_file(board_properties_kobj, &vkeys->kobj_attr.attr);
if (rc)
goto fail_del_kobj;
return 0;
fail_del_kobj:
kobject_del(board_properties_kobj);
fail_free_name:
kfree(name);
vkeys->kobj_attr.attr.name = NULL;
fail_free_data:
kfree(data);
vkeys->data = NULL;
fail:
return rc;
}
static void free_virtual_keys(struct cyttsp5_virtual_keys *vkeys)
{
if (board_properties_kobj)
sysfs_remove_file(board_properties_kobj,
&vkeys->kobj_attr.attr);
kobject_del(board_properties_kobj);
board_properties_kobj = NULL;
kfree(vkeys->data);
kfree(vkeys->kobj_attr.attr.name);
}
#endif
static void *create_and_get_mt_pdata(struct device_node *dev_node)
{
struct cyttsp5_extended_mt_platform_data *ext_pdata;
struct cyttsp5_mt_platform_data *pdata;
u32 value;
int rc;
ext_pdata = kzalloc(sizeof(*ext_pdata), GFP_KERNEL);
if (!ext_pdata) {
rc = -ENOMEM;
goto fail;
}
pdata = &ext_pdata->pdata;
rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
if (rc)
goto fail_free_pdata;
/* Optional fields */
rc = of_property_read_u32(dev_node, "cy,flags", &value);
if (!rc)
pdata->flags = value;
rc = of_property_read_u32(dev_node, "cy,vkeys_x", &value);
if (!rc)
pdata->vkeys_x = value;
rc = of_property_read_u32(dev_node, "cy,vkeys_y", &value);
if (!rc)
pdata->vkeys_y = value;
/* Required fields */
pdata->frmwrk = create_and_get_touch_framework(dev_node);
if (pdata->frmwrk == NULL) {
rc = -EINVAL;
goto fail_free_pdata;
} else if (IS_ERR(pdata->frmwrk)) {
rc = PTR_ERR(pdata->frmwrk);
goto fail_free_pdata;
}
#ifdef ENABLE_VIRTUAL_KEYS
rc = setup_virtual_keys(dev_node, pdata->inp_dev_name,
&ext_pdata->vkeys);
if (rc) {
pr_err("%s: Cannot setup virtual keys!\n", __func__);
goto fail_free_pdata;
}
#endif
return pdata;
fail_free_pdata:
kfree(ext_pdata);
fail:
return ERR_PTR(rc);
}
static void free_mt_pdata(void *pdata)
{
struct cyttsp5_mt_platform_data *mt_pdata =
(struct cyttsp5_mt_platform_data *)pdata;
struct cyttsp5_extended_mt_platform_data *ext_mt_pdata =
container_of(mt_pdata,
struct cyttsp5_extended_mt_platform_data, pdata);
free_touch_framework(mt_pdata->frmwrk);
#ifdef ENABLE_VIRTUAL_KEYS
free_virtual_keys(&ext_mt_pdata->vkeys);
#endif
kfree(ext_mt_pdata);
}
static void *create_and_get_btn_pdata(struct device_node *dev_node)
{
struct cyttsp5_btn_platform_data *pdata;
int rc;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
rc = -ENOMEM;
goto fail;
}
rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
if (rc)
goto fail_free_pdata;
return pdata;
fail_free_pdata:
kfree(pdata);
fail:
return ERR_PTR(rc);
}
static void free_btn_pdata(void *pdata)
{
struct cyttsp5_btn_platform_data *btn_pdata =
(struct cyttsp5_btn_platform_data *)pdata;
kfree(btn_pdata);
}
static void *create_and_get_proximity_pdata(struct device_node *dev_node)
{
struct cyttsp5_proximity_platform_data *pdata;
int rc;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
rc = -ENOMEM;
goto fail;
}
rc = get_inp_dev_name(dev_node, &pdata->inp_dev_name);
if (rc)
goto fail_free_pdata;
pdata->frmwrk = create_and_get_touch_framework(dev_node);
if (pdata->frmwrk == NULL) {
rc = -EINVAL;
goto fail_free_pdata;
} else if (IS_ERR(pdata->frmwrk)) {
rc = PTR_ERR(pdata->frmwrk);
goto fail_free_pdata;
}
return pdata;
fail_free_pdata:
kfree(pdata);
fail:
return ERR_PTR(rc);
}
static void free_proximity_pdata(void *pdata)
{
struct cyttsp5_proximity_platform_data *proximity_pdata =
(struct cyttsp5_proximity_platform_data *)pdata;
free_touch_framework(proximity_pdata->frmwrk);
kfree(proximity_pdata);
}
static struct cyttsp5_device_pdata_func device_pdata_funcs[DEVICE_TYPE_MAX] = {
[DEVICE_MT] = {
.create_and_get_pdata = create_and_get_mt_pdata,
.free_pdata = free_mt_pdata,
},
[DEVICE_BTN] = {
.create_and_get_pdata = create_and_get_btn_pdata,
.free_pdata = free_btn_pdata,
},
[DEVICE_PROXIMITY] = {
.create_and_get_pdata = create_and_get_proximity_pdata,
.free_pdata = free_proximity_pdata,
},
};
static struct cyttsp5_pdata_ptr pdata_ptr[DEVICE_TYPE_MAX];
static const char *device_names[DEVICE_TYPE_MAX] = {
[DEVICE_MT] = "cy,mt",
[DEVICE_BTN] = "cy,btn",
[DEVICE_PROXIMITY] = "cy,proximity",
};
static void set_pdata_ptr(struct cyttsp5_platform_data *pdata)
{
pdata_ptr[DEVICE_MT].pdata = (void **)&pdata->mt_pdata;
pdata_ptr[DEVICE_BTN].pdata = (void **)&pdata->btn_pdata;
pdata_ptr[DEVICE_PROXIMITY].pdata = (void **)&pdata->prox_pdata;
}
static int get_device_type(struct device_node *dev_node,
enum cyttsp5_device_type *type)
{
const char *name;
enum cyttsp5_device_type t;
int rc;
rc = of_property_read_string(dev_node, "name", &name);
if (rc)
return rc;
for (t = 0; t < DEVICE_TYPE_MAX; t++)
if (!strncmp(name, device_names[t], MAX_NAME_LENGTH)) {
*type = t;
return 0;
}
return -EINVAL;
}
static inline void *create_and_get_device_pdata(struct device_node *dev_node,
enum cyttsp5_device_type type)
{
return device_pdata_funcs[type].create_and_get_pdata(dev_node);
}
static inline void free_device_pdata(enum cyttsp5_device_type type)
{
device_pdata_funcs[type].free_pdata(*pdata_ptr[type].pdata);
}
static struct touch_settings *create_and_get_touch_setting(
struct device_node *core_node, const char *name)
{
struct touch_settings *setting;
char *tag_name;
u32 tag_value;
u16 *data;
int size;
int rc;
data = create_and_get_u16_array(core_node, name, &size);
if (IS_ERR_OR_NULL(data))
return (void *)data;
pr_debug("%s: Touch setting:'%s' size:%d\n", __func__, name, size);
setting = kzalloc(sizeof(*setting), GFP_KERNEL);
if (!setting) {
rc = -ENOMEM;
goto fail_free_data;
}
setting->data = (u8 *)data;
setting->size = size;
tag_name = kzalloc(MAX_NAME_LENGTH, GFP_KERNEL);
if (!tag_name) {
rc = -ENOMEM;
goto fail_free_setting;
}
snprintf(tag_name, MAX_NAME_LENGTH, "%s-tag", name);
rc = of_property_read_u32(core_node, tag_name, &tag_value);
if (!rc)
setting->tag = tag_value;
kfree(tag_name);
return setting;
fail_free_setting:
kfree(setting);
fail_free_data:
kfree(data);
return ERR_PTR(rc);
}
static void free_touch_setting(struct touch_settings *setting)
{
if (setting) {
kfree(setting->data);
kfree(setting);
}
}
static char *touch_setting_names[CY_IC_GRPNUM_NUM] = {
NULL, /* CY_IC_GRPNUM_RESERVED */
"cy,cmd_regs", /* CY_IC_GRPNUM_CMD_REGS */
"cy,tch_rep", /* CY_IC_GRPNUM_TCH_REP */
"cy,data_rec", /* CY_IC_GRPNUM_DATA_REC */
"cy,test_rec", /* CY_IC_GRPNUM_TEST_REC */
"cy,pcfg_rec", /* CY_IC_GRPNUM_PCFG_REC */
"cy,tch_parm_val", /* CY_IC_GRPNUM_TCH_PARM_VAL */
"cy,tch_parm_size", /* CY_IC_GRPNUM_TCH_PARM_SIZE */
NULL, /* CY_IC_GRPNUM_RESERVED1 */
NULL, /* CY_IC_GRPNUM_RESERVED2 */
"cy,opcfg_rec", /* CY_IC_GRPNUM_OPCFG_REC */
"cy,ddata_rec", /* CY_IC_GRPNUM_DDATA_REC */
"cy,mdata_rec", /* CY_IC_GRPNUM_MDATA_REC */
"cy,test_regs", /* CY_IC_GRPNUM_TEST_REGS */
"cy,btn_keys", /* CY_IC_GRPNUM_BTN_KEYS */
NULL, /* CY_IC_GRPNUM_TTHE_REGS */
};
static struct cyttsp5_core_platform_data *create_and_get_core_pdata(
struct device_node *core_node)
{
struct cyttsp5_core_platform_data *pdata;
u32 value;
int rc;
int i;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
rc = -ENOMEM;
goto fail;
}
/* Required fields */
rc = of_property_read_u32(core_node, "cy,irq_gpio", &value);
if (rc)
goto fail_free;
pdata->irq_gpio = value;
rc = of_property_read_u32(core_node, "cy,hid_desc_register", &value);
if (rc)
goto fail_free;
pdata->hid_desc_register = value;
/* Optional fields */
/* rst_gpio is optional since a platform may use
* power cycling instead of using the XRES pin
*/
rc = of_property_read_u32(core_node, "cy,rst_gpio", &value);
if (!rc)
pdata->rst_gpio = value;
rc = of_property_read_u32(core_node, "cy,level_irq_udelay", &value);
if (!rc)
pdata->level_irq_udelay = value;
rc = of_property_read_u32(core_node, "cy,vendor_id", &value);
if (!rc)
pdata->vendor_id = value;
rc = of_property_read_u32(core_node, "cy,product_id", &value);
if (!rc)
pdata->product_id = value;
rc = of_property_read_u32(core_node, "cy,flags", &value);
if (!rc)
pdata->flags = value;
rc = of_property_read_u32(core_node, "cy,easy_wakeup_gesture", &value);
if (!rc)
pdata->easy_wakeup_gesture = (u8)value;
for (i = 0; (unsigned int)i < ARRAY_SIZE(touch_setting_names); i++) {
if (touch_setting_names[i] == NULL)
continue;
pdata->sett[i] = create_and_get_touch_setting(core_node,
touch_setting_names[i]);
if (IS_ERR(pdata->sett[i])) {
rc = PTR_ERR(pdata->sett[i]);
goto fail_free_sett;
} else if (pdata->sett[i] == NULL)
pr_debug("%s: No data for setting '%s'\n", __func__,
touch_setting_names[i]);
}
pr_debug("%s: irq_gpio:%d rst_gpio:%d\n"
"hid_desc_register:%d level_irq_udelay:%d vendor_id:%d product_id:%d\n"
"flags:%d easy_wakeup_gesture:%d\n", __func__,
pdata->irq_gpio, pdata->rst_gpio,
pdata->hid_desc_register,
pdata->level_irq_udelay, pdata->vendor_id, pdata->product_id,
pdata->flags, pdata->easy_wakeup_gesture);
pdata->xres = cyttsp5_xres;
pdata->init = cyttsp5_init;
pdata->power = cyttsp5_power;
pdata->detect = cyttsp5_detect;
pdata->irq_stat = cyttsp5_irq_stat;
return pdata;
fail_free_sett:
for (i--; i >= 0; i--)
free_touch_setting(pdata->sett[i]);
fail_free:
kfree(pdata);
fail:
return ERR_PTR(rc);
}
static void free_core_pdata(void *pdata)
{
struct cyttsp5_core_platform_data *core_pdata = pdata;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(touch_setting_names); i++)
free_touch_setting(core_pdata->sett[i]);
kfree(core_pdata);
}
int cyttsp5_devtree_create_and_get_pdata(struct device *adap_dev)
{
struct cyttsp5_platform_data *pdata;
struct device_node *core_node, *dev_node, *dev_node_fail;
enum cyttsp5_device_type type;
int count = 0;
int rc = 0;
if (!adap_dev->of_node)
return 0;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
adap_dev->platform_data = pdata;
set_pdata_ptr(pdata);
/* There should be only one core node */
for_each_child_of_node(adap_dev->of_node, core_node) {
const char *name;
rc = of_property_read_string(core_node, "name", &name);
if (!rc)
pr_debug("%s: name:%s\n", __func__, name);
pdata->core_pdata = create_and_get_core_pdata(core_node);
if (IS_ERR(pdata->core_pdata)) {
rc = PTR_ERR(pdata->core_pdata);
break;
}
/* Increment reference count */
of_node_get(core_node);
for_each_child_of_node(core_node, dev_node) {
count++;
rc = get_device_type(dev_node, &type);
if (rc)
break;
*pdata_ptr[type].pdata
= create_and_get_device_pdata(dev_node, type);
if (IS_ERR(*pdata_ptr[type].pdata))
rc = PTR_ERR(*pdata_ptr[type].pdata);
if (rc)
break;
/* Increment reference count */
of_node_get(dev_node);
}
if (rc) {
free_core_pdata(pdata->core_pdata);
of_node_put(core_node);
for_each_child_of_node(core_node, dev_node_fail) {
if (dev_node == dev_node_fail)
break;
rc = get_device_type(dev_node, &type);
if (rc)
break;
free_device_pdata(type);
of_node_put(dev_node);
}
break;
}
pdata->loader_pdata = &_cyttsp5_loader_platform_data;
}
pr_debug("%s: %d child node(s) found\n", __func__, count);
return rc;
}
EXPORT_SYMBOL_GPL(cyttsp5_devtree_create_and_get_pdata);
int cyttsp5_devtree_clean_pdata(struct device *adap_dev)
{
struct cyttsp5_platform_data *pdata;
struct device_node *core_node, *dev_node;
enum cyttsp5_device_type type;
int rc = 0;
if (!adap_dev->of_node)
return 0;
pdata = dev_get_platdata(adap_dev);
set_pdata_ptr(pdata);
for_each_child_of_node(adap_dev->of_node, core_node) {
free_core_pdata(pdata->core_pdata);
of_node_put(core_node);
for_each_child_of_node(core_node, dev_node) {
rc = get_device_type(dev_node, &type);
if (rc)
break;
free_device_pdata(type);
of_node_put(dev_node);
}
}
return rc;
}
EXPORT_SYMBOL_GPL(cyttsp5_devtree_clean_pdata);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product DeviceTree Driver");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

View file

@ -0,0 +1,222 @@
/*
* cyttsp5_i2c.c
* Parade TrueTouch(TM) Standard Product V5 I2C Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#include <linux/i2c.h>
#include <linux/version.h>
#define CY_I2C_DATA_SIZE (2 * 256)
static int cyttsp5_i2c_read_default(struct device *dev, void *buf, int size)
{
struct i2c_client *client = to_i2c_client(dev);
int rc;
if (!buf || !size || size > CY_I2C_DATA_SIZE)
return -EINVAL;
rc = i2c_master_recv(client, buf, size);
return (rc < 0) ? rc : rc != size ? -EIO : 0;
}
static int cyttsp5_i2c_read_default_nosize(struct device *dev, u8 *buf, u32 max)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_msg msgs[2];
u8 msg_count = 1;
int rc;
u32 size;
if (!buf)
return -EINVAL;
msgs[0].addr = client->addr;
msgs[0].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
msgs[0].len = 2;
msgs[0].buf = buf;
rc = i2c_transfer(client->adapter, msgs, msg_count);
if (rc < 0 || rc != msg_count)
return (rc < 0) ? rc : -EIO;
size = get_unaligned_le16(&buf[0]);
if (!size || size == 2 || size >= CY_PIP_1P7_EMPTY_BUF)
/* Before PIP 1.7, empty buffer is 0x0002;
From PIP 1.7, empty buffer is 0xFFXX */
return 0;
if (size > max)
return -EINVAL;
rc = i2c_master_recv(client, buf, size);
return (rc < 0) ? rc : rc != (int)size ? -EIO : 0;
}
static int cyttsp5_i2c_write_read_specific(struct device *dev, u8 write_len,
u8 *write_buf, u8 *read_buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_msg msgs[2];
u8 msg_count = 1;
int rc;
if (!write_buf || !write_len)
return -EINVAL;
msgs[0].addr = client->addr;
msgs[0].flags = client->flags & I2C_M_TEN;
msgs[0].len = write_len;
msgs[0].buf = write_buf;
rc = i2c_transfer(client->adapter, msgs, msg_count);
if (rc < 0 || rc != msg_count)
return (rc < 0) ? rc : -EIO;
rc = 0;
if (read_buf)
rc = cyttsp5_i2c_read_default_nosize(dev, read_buf,
CY_I2C_DATA_SIZE);
return rc;
}
static struct cyttsp5_bus_ops cyttsp5_i2c_bus_ops = {
.bustype = BUS_I2C,
.read_default = cyttsp5_i2c_read_default,
.read_default_nosize = cyttsp5_i2c_read_default_nosize,
.write_read_specific = cyttsp5_i2c_write_read_specific,
};
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
static const struct of_device_id cyttsp5_i2c_of_match[] = {
{ .compatible = "cy,cyttsp5_i2c_adapter", },
{ }
};
MODULE_DEVICE_TABLE(of, cyttsp5_i2c_of_match);
#endif
static int cyttsp5_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
struct device *dev = &client->dev;
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
const struct of_device_id *match;
#endif
int rc;
pr_err("^^^^^client = %d\n",client->irq);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(dev, "I2C functionality not Supported\n");
return -EIO;
}
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(cyttsp5_i2c_of_match), dev);
if (match) {
rc = cyttsp5_devtree_create_and_get_pdata(dev);
if (rc < 0)
return rc;
}
#endif
rc = cyttsp5_probe(&cyttsp5_i2c_bus_ops, &client->dev, client->irq,
CY_I2C_DATA_SIZE);
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
if (rc && match)
cyttsp5_devtree_clean_pdata(dev);
#endif
return rc;
}
static int cyttsp5_i2c_remove(struct i2c_client *client)
{
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
struct device *dev = &client->dev;
const struct of_device_id *match;
#endif
struct cyttsp5_core_data *cd = i2c_get_clientdata(client);
cyttsp5_release(cd);
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(cyttsp5_i2c_of_match), dev);
if (match)
cyttsp5_devtree_clean_pdata(dev);
#endif
return 0;
}
static const struct i2c_device_id cyttsp5_i2c_id[] = {
{ CYTTSP5_I2C_NAME, 0, },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id);
static struct i2c_driver cyttsp5_i2c_driver = {
.driver = {
.name = CYTTSP5_I2C_NAME,
.owner = THIS_MODULE,
.pm = &cyttsp5_pm_ops,
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
.of_match_table = cyttsp5_i2c_of_match,
#endif
},
.probe = cyttsp5_i2c_probe,
.remove = cyttsp5_i2c_remove,
.id_table = cyttsp5_i2c_id,
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
module_i2c_driver(cyttsp5_i2c_driver);
#else
static int __init cyttsp5_i2c_init(void)
{
int rc = i2c_add_driver(&cyttsp5_i2c_driver);
pr_info("%s: Parade TTSP I2C Driver (Built %s) rc=%d\n",
__func__, CY_DRIVER_VERSION, rc);
return rc;
}
module_init(cyttsp5_i2c_init);
static void __exit cyttsp5_i2c_exit(void)
{
i2c_del_driver(&cyttsp5_i2c_driver);
}
module_exit(cyttsp5_i2c_exit);
#endif
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product I2C driver");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,729 @@
/*
* cyttsp5_mt_common.c
* Parade TrueTouch(TM) Standard Product V5 Multi-Touch Reports Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#define CYTTSP5_MT_NAME "cyttsp5_mt"
#define MT_PARAM_SIGNAL(md, sig_ost) PARAM_SIGNAL(md->pdata->frmwrk, sig_ost)
#define MT_PARAM_MIN(md, sig_ost) PARAM_MIN(md->pdata->frmwrk, sig_ost)
#define MT_PARAM_MAX(md, sig_ost) PARAM_MAX(md->pdata->frmwrk, sig_ost)
#define MT_PARAM_FUZZ(md, sig_ost) PARAM_FUZZ(md->pdata->frmwrk, sig_ost)
#define MT_PARAM_FLAT(md, sig_ost) PARAM_FLAT(md->pdata->frmwrk, sig_ost)
static void cyttsp5_mt_lift_all(struct cyttsp5_mt_data *md)
{
int max = md->si->tch_abs[CY_TCH_T].max;
if (md->num_prv_rec != 0) {
if (md->mt_function.report_slot_liftoff)
md->mt_function.report_slot_liftoff(md, max);
input_sync(md->input);
md->num_prv_rec = 0;
}
}
static void cyttsp5_get_touch_axis(struct cyttsp5_mt_data *md,
int *axis, int size, int max, u8 *xy_data, int bofs)
{
int nbyte;
int next;
for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
dev_vdbg(md->dev,
"%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p xy_data[%d]=%02X(%d) bofs=%d\n",
__func__, *axis, *axis, size, max, xy_data, next,
xy_data[next], xy_data[next], bofs);
*axis = *axis + ((xy_data[next] >> bofs) << (nbyte * 8));
next++;
}
*axis &= max - 1;
dev_vdbg(md->dev,
"%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p xy_data[%d]=%02X(%d)\n",
__func__, *axis, *axis, size, max, xy_data, next,
xy_data[next], xy_data[next]);
}
static void cyttsp5_get_touch_hdr(struct cyttsp5_mt_data *md,
struct cyttsp5_touch *touch, u8 *xy_mode)
{
struct device *dev = md->dev;
struct cyttsp5_sysinfo *si = md->si;
enum cyttsp5_tch_hdr hdr;
for (hdr = CY_TCH_TIME; hdr < CY_TCH_NUM_HDR; hdr++) {
if (!si->tch_hdr[hdr].report)
continue;
cyttsp5_get_touch_axis(md, &touch->hdr[hdr],
si->tch_hdr[hdr].size,
si->tch_hdr[hdr].max,
xy_mode + si->tch_hdr[hdr].ofs,
si->tch_hdr[hdr].bofs);
dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
cyttsp5_tch_hdr_string[hdr],
touch->hdr[hdr], touch->hdr[hdr]);
}
dev_dbg(dev,
"%s: time=%X tch_num=%d lo=%d noise=%d counter=%d\n",
__func__,
touch->hdr[CY_TCH_TIME],
touch->hdr[CY_TCH_NUM],
touch->hdr[CY_TCH_LO],
touch->hdr[CY_TCH_NOISE],
touch->hdr[CY_TCH_COUNTER]);
}
static void cyttsp5_get_touch_record(struct cyttsp5_mt_data *md,
struct cyttsp5_touch *touch, u8 *xy_data)
{
struct device *dev = md->dev;
struct cyttsp5_sysinfo *si = md->si;
enum cyttsp5_tch_abs abs;
for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
if (!si->tch_abs[abs].report)
continue;
cyttsp5_get_touch_axis(md, &touch->abs[abs],
si->tch_abs[abs].size,
si->tch_abs[abs].max,
xy_data + si->tch_abs[abs].ofs,
si->tch_abs[abs].bofs);
dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
cyttsp5_tch_abs_string[abs],
touch->abs[abs], touch->abs[abs]);
}
}
static void cyttsp5_mt_process_touch(struct cyttsp5_mt_data *md,
struct cyttsp5_touch *touch)
{
struct device *dev = md->dev;
struct cyttsp5_sysinfo *si = md->si;
int tmp;
bool flipped;
/* Orientation is signed */
touch->abs[CY_TCH_OR] = (int8_t)touch->abs[CY_TCH_OR];
if (md->pdata->flags & CY_MT_FLAG_FLIP) {
tmp = touch->abs[CY_TCH_X];
touch->abs[CY_TCH_X] = touch->abs[CY_TCH_Y];
touch->abs[CY_TCH_Y] = tmp;
if (touch->abs[CY_TCH_OR] > 0)
touch->abs[CY_TCH_OR] =
md->or_max - touch->abs[CY_TCH_OR];
else
touch->abs[CY_TCH_OR] =
md->or_min - touch->abs[CY_TCH_OR];
flipped = true;
} else
flipped = false;
if (md->pdata->flags & CY_MT_FLAG_INV_X) {
if (flipped)
touch->abs[CY_TCH_X] = si->sensing_conf_data.res_y -
touch->abs[CY_TCH_X];
else
touch->abs[CY_TCH_X] = si->sensing_conf_data.res_x -
touch->abs[CY_TCH_X];
touch->abs[CY_TCH_OR] *= -1;
}
if (md->pdata->flags & CY_MT_FLAG_INV_Y) {
if (flipped)
touch->abs[CY_TCH_Y] = si->sensing_conf_data.res_x -
touch->abs[CY_TCH_Y];
else
touch->abs[CY_TCH_Y] = si->sensing_conf_data.res_y -
touch->abs[CY_TCH_Y];
touch->abs[CY_TCH_OR] *= -1;
}
/* Convert MAJOR/MINOR from mm to resolution */
tmp = touch->abs[CY_TCH_MAJ] * 100 * si->sensing_conf_data.res_x;
touch->abs[CY_TCH_MAJ] = tmp / si->sensing_conf_data.len_x;
tmp = touch->abs[CY_TCH_MIN] * 100 * si->sensing_conf_data.res_x;
touch->abs[CY_TCH_MIN] = tmp / si->sensing_conf_data.len_x;
dev_vdbg(dev, "%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n",
__func__, flipped ? "true" : "false",
md->pdata->flags & CY_MT_FLAG_INV_X ? "true" : "false",
md->pdata->flags & CY_MT_FLAG_INV_Y ? "true" : "false",
touch->abs[CY_TCH_X], touch->abs[CY_TCH_X],
touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]);
}
static void cyttsp5_report_event(struct cyttsp5_mt_data *md, int event,
int value)
{
int sig = MT_PARAM_SIGNAL(md, event);
if (sig != CY_IGNORE_VALUE)
input_report_abs(md->input, sig, value);
}
static void cyttsp5_get_mt_touches(struct cyttsp5_mt_data *md,
struct cyttsp5_touch *tch, int num_cur_tch)
{
struct device *dev = md->dev;
struct cyttsp5_sysinfo *si = md->si;
int sig;
int i, j, t = 0;
DECLARE_BITMAP(ids, si->tch_abs[CY_TCH_T].max);
int mt_sync_count = 0;
u8 *tch_addr;
bitmap_zero(ids, si->tch_abs[CY_TCH_T].max);
memset(tch->abs, 0, sizeof(tch->abs));
for (i = 0; i < num_cur_tch; i++) {
tch_addr = si->xy_data + (i * si->desc.tch_record_size);
cyttsp5_get_touch_record(md, tch, tch_addr);
/* Discard proximity event */
if (tch->abs[CY_TCH_O] == CY_OBJ_PROXIMITY) {
dev_vdbg(dev, "%s: Discarding proximity event\n",
__func__);
continue;
}
/* Validate track_id */
t = tch->abs[CY_TCH_T];
if (t < md->t_min || t > md->t_max) {
dev_err(dev, "%s: tch=%d -> bad trk_id=%d max_id=%d\n",
__func__, i, t, md->t_max);
if (md->mt_function.input_sync)
md->mt_function.input_sync(md->input);
mt_sync_count++;
continue;
}
/* Lift-off */
if (tch->abs[CY_TCH_E] == CY_EV_LIFTOFF) {
dev_dbg(dev, "%s: t=%d e=%d lift-off\n",
__func__, t, tch->abs[CY_TCH_E]);
goto cyttsp5_get_mt_touches_pr_tch;
}
/* Process touch */
cyttsp5_mt_process_touch(md, tch);
/* use 0 based track id's */
t -= md->t_min;
sig = MT_PARAM_SIGNAL(md, CY_ABS_ID_OST);
if (sig != CY_IGNORE_VALUE) {
if (md->mt_function.input_report)
md->mt_function.input_report(md->input, sig,
t, tch->abs[CY_TCH_O]);
__set_bit(t, ids);
}
/* If touch type is hover, send P as distance, reset P */
if (tch->abs[CY_TCH_O] == CY_OBJ_HOVER) {
/* CY_ABS_D_OST signal must be in touch framework */
cyttsp5_report_event(md, CY_ABS_D_OST,
tch->abs[CY_TCH_P]);
tch->abs[CY_TCH_P] = 0;
} else
cyttsp5_report_event(md, CY_ABS_D_OST, 0);
/* all devices: position and pressure fields */
for (j = 0; j <= CY_ABS_W_OST; j++) {
if (!si->tch_abs[j].report)
continue;
cyttsp5_report_event(md, CY_ABS_X_OST + j,
tch->abs[CY_TCH_X + j]);
}
/* Get the extended touch fields */
for (j = 0; j < CY_NUM_EXT_TCH_FIELDS; j++) {
if (!si->tch_abs[CY_ABS_MAJ_OST + j].report)
continue;
cyttsp5_report_event(md, CY_ABS_MAJ_OST + j,
tch->abs[CY_TCH_MAJ + j]);
}
if (md->mt_function.input_sync)
md->mt_function.input_sync(md->input);
mt_sync_count++;
cyttsp5_get_mt_touches_pr_tch:
dev_dbg(dev,
"%s: t=%d x=%d y=%d z=%d M=%d m=%d o=%d e=%d obj=%d tip=%d\n",
__func__, t,
tch->abs[CY_TCH_X],
tch->abs[CY_TCH_Y],
tch->abs[CY_TCH_P],
tch->abs[CY_TCH_MAJ],
tch->abs[CY_TCH_MIN],
tch->abs[CY_TCH_OR],
tch->abs[CY_TCH_E],
tch->abs[CY_TCH_O],
tch->abs[CY_TCH_TIP]);
}
if (md->mt_function.final_sync)
md->mt_function.final_sync(md->input,
si->tch_abs[CY_TCH_T].max, mt_sync_count, ids);
md->num_prv_rec = num_cur_tch;
}
/* read xy_data for all current touches */
static int cyttsp5_xy_worker(struct cyttsp5_mt_data *md)
{
struct device *dev = md->dev;
struct cyttsp5_sysinfo *si = md->si;
int max_tch = si->sensing_conf_data.max_tch;
struct cyttsp5_touch tch;
u8 num_cur_tch;
int rc = 0;
cyttsp5_get_touch_hdr(md, &tch, si->xy_mode + 3);
num_cur_tch = tch.hdr[CY_TCH_NUM];
if (num_cur_tch > max_tch) {
dev_err(dev, "%s: Num touch err detected (n=%d)\n",
__func__, num_cur_tch);
num_cur_tch = max_tch;
}
if (tch.hdr[CY_TCH_LO]) {
dev_dbg(dev, "%s: Large area detected\n", __func__);
if (md->pdata->flags & CY_MT_FLAG_NO_TOUCH_ON_LO)
num_cur_tch = 0;
}
if (num_cur_tch == 0 && md->num_prv_rec == 0)
goto cyttsp5_xy_worker_exit;
/* extract xy_data for all currently reported touches */
dev_vdbg(dev, "%s: extract data num_cur_tch=%d\n", __func__,
num_cur_tch);
if (num_cur_tch)
cyttsp5_get_mt_touches(md, &tch, num_cur_tch);
else
cyttsp5_mt_lift_all(md);
rc = 0;
cyttsp5_xy_worker_exit:
return rc;
}
static void cyttsp5_mt_send_dummy_event(struct cyttsp5_core_data *cd,
struct cyttsp5_mt_data *md)
{
#ifndef EASYWAKE_TSG6
/* TSG5 EasyWake */
unsigned long ids = 0;
/* for easy wakeup */
if (md->mt_function.input_report)
md->mt_function.input_report(md->input, ABS_MT_TRACKING_ID,
0, CY_OBJ_STANDARD_FINGER);
if (md->mt_function.input_sync)
md->mt_function.input_sync(md->input);
if (md->mt_function.final_sync)
md->mt_function.final_sync(md->input, 0, 1, &ids);
if (md->mt_function.report_slot_liftoff)
md->mt_function.report_slot_liftoff(md, 1);
if (md->mt_function.final_sync)
md->mt_function.final_sync(md->input, 1, 1, &ids);
#else
/* TSG6 FW1.3 EasyWake */
u8 key_value;
switch (cd->gesture_id) {
case GESTURE_DOUBLE_TAP:
key_value = KEY_F1;
break;
case GESTURE_TWO_FINGERS_SLIDE:
key_value = KEY_F2;
break;
case GESTURE_TOUCH_DETECTED:
key_value = KEY_F3;
break;
case GESTURE_PUSH_BUTTON:
key_value = KEY_F4;
break;
case GESTURE_SINGLE_SLIDE_DE_TX:
key_value = KEY_F5;
break;
case GESTURE_SINGLE_SLIDE_IN_TX:
key_value = KEY_F6;
break;
case GESTURE_SINGLE_SLIDE_DE_RX:
key_value = KEY_F7;
break;
case GESTURE_SINGLE_SLIDE_IN_RX:
key_value = KEY_F8;
break;
default:
break;
}
input_report_key(md->input, key_value, 1);
mdelay(10);
input_report_key(md->input, key_value, 0);
input_sync(md->input);
#endif
}
static int cyttsp5_mt_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
int rc;
if (md->si->xy_mode[2] != md->si->desc.tch_report_id)
return 0;
/* core handles handshake */
mutex_lock(&md->mt_lock);
rc = cyttsp5_xy_worker(md);
mutex_unlock(&md->mt_lock);
if (rc < 0)
dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
return rc;
}
static int cyttsp5_mt_wake_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
mutex_lock(&md->mt_lock);
cyttsp5_mt_send_dummy_event(cd, md);
mutex_unlock(&md->mt_lock);
return 0;
}
static int cyttsp5_startup_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
mutex_lock(&md->mt_lock);
cyttsp5_mt_lift_all(md);
mutex_unlock(&md->mt_lock);
return 0;
}
static int cyttsp5_mt_suspend_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
mutex_lock(&md->mt_lock);
cyttsp5_mt_lift_all(md);
md->is_suspended = true;
mutex_unlock(&md->mt_lock);
pm_runtime_put(dev);
return 0;
}
static int cyttsp5_mt_resume_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
pm_runtime_get(dev);
mutex_lock(&md->mt_lock);
md->is_suspended = false;
mutex_unlock(&md->mt_lock);
return 0;
}
static int cyttsp5_mt_open(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
pm_runtime_get_sync(dev);
mutex_lock(&md->mt_lock);
md->is_suspended = false;
mutex_unlock(&md->mt_lock);
dev_vdbg(dev, "%s: setup subscriptions\n", __func__);
/* set up touch call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_MT_NAME,
cyttsp5_mt_attention, CY_MODE_OPERATIONAL);
/* set up startup call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_MT_NAME,
cyttsp5_startup_attention, 0);
/* set up wakeup call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_WAKE, CYTTSP5_MT_NAME,
cyttsp5_mt_wake_attention, 0);
/* set up suspend call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_SUSPEND, CYTTSP5_MT_NAME,
cyttsp5_mt_suspend_attention, 0);
/* set up resume call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_RESUME, CYTTSP5_MT_NAME,
cyttsp5_mt_resume_attention, 0);
return 0;
}
static void cyttsp5_mt_close(struct input_dev *input)
{
struct device *dev = input->dev.parent;
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_MT_NAME,
cyttsp5_mt_attention, CY_MODE_OPERATIONAL);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_MT_NAME,
cyttsp5_startup_attention, 0);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_WAKE, CYTTSP5_MT_NAME,
cyttsp5_mt_wake_attention, 0);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_SUSPEND, CYTTSP5_MT_NAME,
cyttsp5_mt_suspend_attention, 0);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_RESUME, CYTTSP5_MT_NAME,
cyttsp5_mt_resume_attention, 0);
mutex_lock(&md->mt_lock);
if (!md->is_suspended) {
pm_runtime_put(dev);
md->is_suspended = true;
}
mutex_unlock(&md->mt_lock);
}
static int cyttsp5_setup_input_device(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
int signal = CY_IGNORE_VALUE;
int max_x, max_y, max_p, min, max;
int max_x_tmp, max_y_tmp;
int i;
int rc;
dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
__set_bit(EV_ABS, md->input->evbit);
__set_bit(EV_REL, md->input->evbit);
__set_bit(EV_KEY, md->input->evbit);
#ifdef INPUT_PROP_DIRECT
__set_bit(INPUT_PROP_DIRECT, md->input->propbit);
#endif
/* If virtualkeys enabled, don't use all screen */
if (md->pdata->flags & CY_MT_FLAG_VKEYS) {
max_x_tmp = md->pdata->vkeys_x;
max_y_tmp = md->pdata->vkeys_y;
} else {
max_x_tmp = md->si->sensing_conf_data.res_x;
max_y_tmp = md->si->sensing_conf_data.res_y;
}
/* get maximum values from the sysinfo data */
if (md->pdata->flags & CY_MT_FLAG_FLIP) {
max_x = max_y_tmp - 1;
max_y = max_x_tmp - 1;
} else {
max_x = max_x_tmp - 1;
max_y = max_y_tmp - 1;
}
max_p = md->si->sensing_conf_data.max_z;
/* set event signal capabilities */
for (i = 0; i < NUM_SIGNALS(md->pdata->frmwrk); i++) {
signal = MT_PARAM_SIGNAL(md, i);
if (signal != CY_IGNORE_VALUE) {
__set_bit(signal, md->input->absbit);
min = MT_PARAM_MIN(md, i);
max = MT_PARAM_MAX(md, i);
if (i == CY_ABS_ID_OST) {
/* shift track ids down to start at 0 */
max = max - min;
min = min - min;
} else if (i == CY_ABS_X_OST)
max = max_x;
else if (i == CY_ABS_Y_OST)
max = max_y;
else if (i == CY_ABS_P_OST)
max = max_p;
input_set_abs_params(md->input, signal, min, max,
MT_PARAM_FUZZ(md, i), MT_PARAM_FLAT(md, i));
dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n",
__func__, signal, min, max);
}
}
md->or_min = MT_PARAM_MIN(md, CY_ABS_OR_OST);
md->or_max = MT_PARAM_MAX(md, CY_ABS_OR_OST);
md->t_min = MT_PARAM_MIN(md, CY_ABS_ID_OST);
md->t_max = MT_PARAM_MAX(md, CY_ABS_ID_OST);
rc = md->mt_function.input_register_device(md->input,
md->si->tch_abs[CY_TCH_T].max);
if (rc < 0)
dev_err(dev, "%s: Error, failed register input device r=%d\n",
__func__, rc);
else
md->input_device_registered = true;
#ifdef EASYWAKE_TSG6
input_set_capability(md->input, EV_KEY, KEY_F1);
input_set_capability(md->input, EV_KEY, KEY_F2);
input_set_capability(md->input, EV_KEY, KEY_F3);
input_set_capability(md->input, EV_KEY, KEY_F4);
input_set_capability(md->input, EV_KEY, KEY_F5);
input_set_capability(md->input, EV_KEY, KEY_F6);
input_set_capability(md->input, EV_KEY, KEY_F7);
input_set_capability(md->input, EV_KEY, KEY_F8);
#endif
return rc;
}
static int cyttsp5_setup_input_attention(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
int rc;
md->si = _cyttsp5_request_sysinfo(dev);
if (!md->si)
return -EINVAL;
rc = cyttsp5_setup_input_device(dev);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_MT_NAME,
cyttsp5_setup_input_attention, 0);
return rc;
}
int cyttsp5_mt_probe(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
struct cyttsp5_mt_platform_data *mt_pdata;
int rc = 0;
if (!pdata || !pdata->mt_pdata) {
dev_err(dev, "%s: Missing platform data\n", __func__);
rc = -ENODEV;
goto error_no_pdata;
}
mt_pdata = pdata->mt_pdata;
cyttsp5_init_function_ptrs(md);
mutex_init(&md->mt_lock);
md->dev = dev;
md->pdata = mt_pdata;
/* Create the input device and register it. */
dev_vdbg(dev, "%s: Create the input device and register it\n",
__func__);
md->input = input_allocate_device();
if (!md->input) {
dev_err(dev, "%s: Error, failed to allocate input device\n",
__func__);
rc = -ENODEV;
goto error_alloc_failed;
}
if (md->pdata->inp_dev_name)
md->input->name = md->pdata->inp_dev_name;
else
md->input->name = CYTTSP5_MT_NAME;
scnprintf(md->phys, sizeof(md->phys), "%s/input%d", dev_name(dev),
cd->phys_num++);
md->input->phys = md->phys;
md->input->dev.parent = md->dev;
md->input->open = cyttsp5_mt_open;
md->input->close = cyttsp5_mt_close;
input_set_drvdata(md->input, md);
/* get sysinfo */
md->si = _cyttsp5_request_sysinfo(dev);
if (md->si) {
rc = cyttsp5_setup_input_device(dev);
if (rc)
goto error_init_input;
} else {
dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
__func__, md->si);
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_MT_NAME, cyttsp5_setup_input_attention, 0);
}
return 0;
error_init_input:
input_free_device(md->input);
error_alloc_failed:
error_no_pdata:
dev_err(dev, "%s failed.\n", __func__);
return rc;
}
int cyttsp5_mt_release(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_mt_data *md = &cd->md;
if (md->input_device_registered) {
input_unregister_device(md->input);
} else {
input_free_device(md->input);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_MT_NAME, cyttsp5_setup_input_attention, 0);
}
return 0;
}

View file

@ -0,0 +1,85 @@
/*
* cyttsp5_mta.c
* Parade TrueTouch(TM) Standard Product V5 Multi-Touch Protocol A Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
static void cyttsp5_final_sync(struct input_dev *input, int max_slots,
int mt_sync_count, unsigned long *ids)
{
if (mt_sync_count)
input_sync(input);
}
static void cyttsp5_input_sync(struct input_dev *input)
{
input_mt_sync(input);
}
static void cyttsp5_input_report(struct input_dev *input, int sig,
int t, int type)
{
if (type == CY_OBJ_STANDARD_FINGER || type == CY_OBJ_GLOVE
|| type == CY_OBJ_HOVER) {
input_report_key(input, BTN_TOOL_FINGER, CY_BTN_PRESSED);
input_report_key(input, BTN_TOOL_PEN, CY_BTN_RELEASED);
} else if (type == CY_OBJ_STYLUS) {
input_report_key(input, BTN_TOOL_PEN, CY_BTN_PRESSED);
input_report_key(input, BTN_TOOL_FINGER, CY_BTN_RELEASED);
}
if (type != CY_OBJ_HOVER)
input_report_key(input, BTN_TOUCH, CY_BTN_PRESSED);
input_report_abs(input, sig, t);
}
static void cyttsp5_report_slot_liftoff(struct cyttsp5_mt_data *md,
int max_slots)
{
input_report_key(md->input, BTN_TOUCH, CY_BTN_RELEASED);
input_report_key(md->input, BTN_TOOL_FINGER, CY_BTN_RELEASED);
input_report_key(md->input, BTN_TOOL_PEN, CY_BTN_RELEASED);
}
static int cyttsp5_input_register_device(struct input_dev *input, int max_slots)
{
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);
__set_bit(BTN_TOOL_PEN, input->keybit);
return input_register_device(input);
}
void cyttsp5_init_function_ptrs(struct cyttsp5_mt_data *md)
{
md->mt_function.report_slot_liftoff = cyttsp5_report_slot_liftoff;
md->mt_function.final_sync = cyttsp5_final_sync;
md->mt_function.input_sync = cyttsp5_input_sync;
md->mt_function.input_report = cyttsp5_input_report;
md->mt_function.input_register_device = cyttsp5_input_register_device;
}

View file

@ -0,0 +1,93 @@
/*
* cyttsp5_mtb.c
* Parade TrueTouch(TM) Standard Product V5 Multi-Touch Protocol B Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#include <linux/input/mt.h>
#include <linux/version.h>
static void cyttsp5_final_sync(struct input_dev *input, int max_slots,
int mt_sync_count, unsigned long *ids)
{
int t;
for (t = 0; t < max_slots; t++) {
if (test_bit(t, ids))
continue;
input_mt_slot(input, t);
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
}
input_sync(input);
}
static void cyttsp5_input_report(struct input_dev *input, int sig,
int t, int type)
{
input_mt_slot(input, t);
if (type == CY_OBJ_STANDARD_FINGER || type == CY_OBJ_GLOVE
|| type == CY_OBJ_HOVER)
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
else if (type == CY_OBJ_STYLUS)
input_mt_report_slot_state(input, MT_TOOL_PEN, true);
}
static void cyttsp5_report_slot_liftoff(struct cyttsp5_mt_data *md,
int max_slots)
{
int t;
if (md->num_prv_rec == 0)
return;
for (t = 0; t < max_slots; t++) {
input_mt_slot(md->input, t);
input_mt_report_slot_state(md->input,
MT_TOOL_FINGER, false);
}
}
static int cyttsp5_input_register_device(struct input_dev *input, int max_slots)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
input_mt_init_slots(input, max_slots, 0);
#else
input_mt_init_slots(input, max_slots);
#endif
return input_register_device(input);
}
void cyttsp5_init_function_ptrs(struct cyttsp5_mt_data *md)
{
md->mt_function.report_slot_liftoff = cyttsp5_report_slot_liftoff;
md->mt_function.final_sync = cyttsp5_final_sync;
md->mt_function.input_sync = NULL;
md->mt_function.input_report = cyttsp5_input_report;
md->mt_function.input_register_device = cyttsp5_input_register_device;
}

View file

@ -0,0 +1,288 @@
/*
* cyttsp5_platform.c
* Parade TrueTouch(TM) Standard Product V5 Platform Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2013-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#include <linux/cyttsp5_platform.h>
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
/* FW for Panel ID = 0x00 */
#include "cyttsp5_fw_pid00.h"
static struct cyttsp5_touch_firmware cyttsp5_firmware_pid00 = {
.img = cyttsp4_img_pid00,
.size = ARRAY_SIZE(cyttsp4_img_pid00),
.ver = cyttsp4_ver_pid00,
.vsize = ARRAY_SIZE(cyttsp4_ver_pid00),
.panel_id = 0x00,
};
/* FW for Panel ID = 0x01 */
#include "cyttsp5_fw_pid01.h"
static struct cyttsp5_touch_firmware cyttsp5_firmware_pid01 = {
.img = cyttsp4_img_pid01,
.size = ARRAY_SIZE(cyttsp4_img_pid01),
.ver = cyttsp4_ver_pid01,
.vsize = ARRAY_SIZE(cyttsp4_ver_pid01),
.panel_id = 0x01,
};
/* FW for Panel ID not enabled (legacy) */
#include "cyttsp5_fw.h"
static struct cyttsp5_touch_firmware cyttsp5_firmware = {
.img = cyttsp4_img,
.size = ARRAY_SIZE(cyttsp4_img),
.ver = cyttsp4_ver,
.vsize = ARRAY_SIZE(cyttsp4_ver),
};
#else
/* FW for Panel ID not enabled (legacy) */
static struct cyttsp5_touch_firmware cyttsp5_firmware = {
.img = NULL,
.size = 0,
.ver = NULL,
.vsize = 0,
};
#endif
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE
/* TT Config for Panel ID = 0x00 */
#include "cyttsp5_params_pid00.h"
static struct touch_settings cyttsp5_sett_param_regs_pid00 = {
.data = (uint8_t *)&cyttsp4_param_regs_pid00[0],
.size = ARRAY_SIZE(cyttsp4_param_regs_pid00),
.tag = 0,
};
static struct touch_settings cyttsp5_sett_param_size_pid00 = {
.data = (uint8_t *)&cyttsp4_param_size_pid00[0],
.size = ARRAY_SIZE(cyttsp4_param_size_pid00),
.tag = 0,
};
static struct cyttsp5_touch_config cyttsp5_ttconfig_pid00 = {
.param_regs = &cyttsp5_sett_param_regs_pid00,
.param_size = &cyttsp5_sett_param_size_pid00,
.fw_ver = ttconfig_fw_ver_pid00,
.fw_vsize = ARRAY_SIZE(ttconfig_fw_ver_pid00),
.panel_id = 0x00,
};
/* TT Config for Panel ID = 0x01 */
#include "cyttsp5_params_pid01.h"
static struct touch_settings cyttsp5_sett_param_regs_pid01 = {
.data = (uint8_t *)&cyttsp4_param_regs_pid01[0],
.size = ARRAY_SIZE(cyttsp4_param_regs_pid01),
.tag = 0,
};
static struct touch_settings cyttsp5_sett_param_size_pid01 = {
.data = (uint8_t *)&cyttsp4_param_size_pid01[0],
.size = ARRAY_SIZE(cyttsp4_param_size_pid01),
.tag = 0,
};
static struct cyttsp5_touch_config cyttsp5_ttconfig_pid01 = {
.param_regs = &cyttsp5_sett_param_regs_pid01,
.param_size = &cyttsp5_sett_param_size_pid01,
.fw_ver = ttconfig_fw_ver_pid01,
.fw_vsize = ARRAY_SIZE(ttconfig_fw_ver_pid01),
.panel_id = 0x01,
};
/* TT Config for Panel ID not enabled (legacy)*/
#include "cyttsp5_params.h"
static struct touch_settings cyttsp5_sett_param_regs = {
.data = (uint8_t *)&cyttsp4_param_regs[0],
.size = ARRAY_SIZE(cyttsp4_param_regs),
.tag = 0,
};
static struct touch_settings cyttsp5_sett_param_size = {
.data = (uint8_t *)&cyttsp4_param_size[0],
.size = ARRAY_SIZE(cyttsp4_param_size),
.tag = 0,
};
static struct cyttsp5_touch_config cyttsp5_ttconfig = {
.param_regs = &cyttsp5_sett_param_regs,
.param_size = &cyttsp5_sett_param_size,
.fw_ver = ttconfig_fw_ver,
.fw_vsize = ARRAY_SIZE(ttconfig_fw_ver),
};
#else
/* TT Config for Panel ID not enabled (legacy)*/
static struct cyttsp5_touch_config cyttsp5_ttconfig = {
.param_regs = NULL,
.param_size = NULL,
.fw_ver = NULL,
.fw_vsize = 0,
};
#endif
static struct cyttsp5_touch_firmware *cyttsp5_firmwares[] = {
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
&cyttsp5_firmware_pid00,
&cyttsp5_firmware_pid01,
#endif
NULL, /* Last item should always be NULL */
};
static struct cyttsp5_touch_config *cyttsp5_ttconfigs[] = {
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE
&cyttsp5_ttconfig_pid00,
&cyttsp5_ttconfig_pid01,
#endif
NULL, /* Last item should always be NULL */
};
struct cyttsp5_loader_platform_data _cyttsp5_loader_platform_data = {
.fw = &cyttsp5_firmware,
.ttconfig = &cyttsp5_ttconfig,
.fws = cyttsp5_firmwares,
.ttconfigs = cyttsp5_ttconfigs,
.flags = CY_LOADER_FLAG_NONE,
};
int cyttsp5_xres(struct cyttsp5_core_platform_data *pdata,
struct device *dev)
{
int rst_gpio = pdata->rst_gpio;
int rc = 0;
gpio_set_value(rst_gpio, 1);
msleep(20);
gpio_set_value(rst_gpio, 0);
msleep(40);
gpio_set_value(rst_gpio, 1);
msleep(20);
dev_info(dev,
"%s: RESET CYTTSP gpio=%d r=%d\n", __func__,
pdata->rst_gpio, rc);
return rc;
}
int cyttsp5_init(struct cyttsp5_core_platform_data *pdata,
int on, struct device *dev)
{
int rst_gpio = pdata->rst_gpio;
int irq_gpio = pdata->irq_gpio;
int rc = 0;
if (on) {
rc = gpio_request(rst_gpio, NULL);
if (rc < 0) {
gpio_free(rst_gpio);
rc = gpio_request(rst_gpio, NULL);
}
if (rc < 0) {
dev_err(dev,
"%s: Fail request gpio=%d\n", __func__,
rst_gpio);
} else {
rc = gpio_direction_output(rst_gpio, 1);
if (rc < 0) {
pr_err("%s: Fail set output gpio=%d\n",
__func__, rst_gpio);
gpio_free(rst_gpio);
} else {
rc = gpio_request(irq_gpio, NULL);
if (rc < 0) {
gpio_free(irq_gpio);
rc = gpio_request(irq_gpio,
NULL);
}
if (rc < 0) {
dev_err(dev,
"%s: Fail request gpio=%d\n",
__func__, irq_gpio);
gpio_free(rst_gpio);
} else {
gpio_direction_input(irq_gpio);
}
}
}
} else {
gpio_free(rst_gpio);
gpio_free(irq_gpio);
}
dev_info(dev, "%s: INIT CYTTSP RST gpio=%d and IRQ gpio=%d r=%d\n",
__func__, rst_gpio, irq_gpio, rc);
return rc;
}
static int cyttsp5_wakeup(struct cyttsp5_core_platform_data *pdata,
struct device *dev, atomic_t *ignore_irq)
{
return 0;
}
static int cyttsp5_sleep(struct cyttsp5_core_platform_data *pdata,
struct device *dev, atomic_t *ignore_irq)
{
return 0;
}
int cyttsp5_power(struct cyttsp5_core_platform_data *pdata,
int on, struct device *dev, atomic_t *ignore_irq)
{
if (on)
return cyttsp5_wakeup(pdata, dev, ignore_irq);
return cyttsp5_sleep(pdata, dev, ignore_irq);
}
int cyttsp5_irq_stat(struct cyttsp5_core_platform_data *pdata,
struct device *dev)
{
return gpio_get_value(pdata->irq_gpio);
}
#ifdef CYTTSP5_DETECT_HW
int cyttsp5_detect(struct cyttsp5_core_platform_data *pdata,
struct device *dev, cyttsp5_platform_read read)
{
int retry = 3;
int rc;
char buf[1];
while (retry--) {
/* Perform reset, wait for 100 ms and perform read */
dev_vdbg(dev, "%s: Performing a reset\n", __func__);
pdata->xres(pdata, dev);
msleep(100);
rc = read(dev, buf, 1);
if (!rc)
return 0;
dev_vdbg(dev, "%s: Read unsuccessful, try=%d\n",
__func__, 3 - retry);
}
return rc;
}
#endif

View file

@ -0,0 +1,553 @@
/*
* cyttsp5_proximity.c
* Parade TrueTouch(TM) Standard Product V5 Proximity Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2013-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#define CYTTSP5_PROXIMITY_NAME "cyttsp5_proximity"
/* Timeout value in ms. */
#define CYTTSP5_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT 1000
#define CYTTSP5_PROXIMITY_ON 0
#define CYTTSP5_PROXIMITY_OFF 1
static inline struct cyttsp5_proximity_data *get_prox_data(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
return &cd->pd;
}
static void cyttsp5_report_proximity(struct cyttsp5_proximity_data *pd,
bool on)
{
int val = on ? CYTTSP5_PROXIMITY_ON : CYTTSP5_PROXIMITY_OFF;
input_report_abs(pd->input, ABS_DISTANCE, val);
input_sync(pd->input);
}
static void cyttsp5_get_touch_axis(struct cyttsp5_proximity_data *pd,
int *axis, int size, int max, u8 *xy_data, int bofs)
{
int nbyte;
int next;
for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
dev_vdbg(pd->dev,
"%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p xy_data[%d]=%02X(%d) bofs=%d\n",
__func__, *axis, *axis, size, max, xy_data, next,
xy_data[next], xy_data[next], bofs);
*axis = *axis + ((xy_data[next] >> bofs) << (nbyte * 8));
next++;
}
*axis &= max - 1;
dev_vdbg(pd->dev,
"%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p xy_data[%d]=%02X(%d)\n",
__func__, *axis, *axis, size, max, xy_data, next,
xy_data[next], xy_data[next]);
}
static void cyttsp5_get_touch_hdr(struct cyttsp5_proximity_data *pd,
struct cyttsp5_touch *touch, u8 *xy_mode)
{
struct device *dev = pd->dev;
struct cyttsp5_sysinfo *si = pd->si;
enum cyttsp5_tch_hdr hdr;
for (hdr = CY_TCH_TIME; hdr < CY_TCH_NUM_HDR; hdr++) {
if (!si->tch_hdr[hdr].report)
continue;
cyttsp5_get_touch_axis(pd, &touch->hdr[hdr],
si->tch_hdr[hdr].size,
si->tch_hdr[hdr].max,
xy_mode + si->tch_hdr[hdr].ofs,
si->tch_hdr[hdr].bofs);
dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
cyttsp5_tch_hdr_string[hdr],
touch->hdr[hdr], touch->hdr[hdr]);
}
}
static void cyttsp5_get_touch(struct cyttsp5_proximity_data *pd,
struct cyttsp5_touch *touch, u8 *xy_data)
{
struct device *dev = pd->dev;
struct cyttsp5_sysinfo *si = pd->si;
enum cyttsp5_tch_abs abs;
for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
if (!si->tch_abs[abs].report)
continue;
cyttsp5_get_touch_axis(pd, &touch->abs[abs],
si->tch_abs[abs].size,
si->tch_abs[abs].max,
xy_data + si->tch_abs[abs].ofs,
si->tch_abs[abs].bofs);
dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
cyttsp5_tch_abs_string[abs],
touch->abs[abs], touch->abs[abs]);
}
dev_vdbg(dev, "%s: x=%04X(%d) y=%04X(%d)\n", __func__,
touch->abs[CY_TCH_X], touch->abs[CY_TCH_X],
touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]);
}
static void cyttsp5_get_proximity_touch(struct cyttsp5_proximity_data *pd,
struct cyttsp5_touch *tch, int num_cur_tch)
{
struct cyttsp5_sysinfo *si = pd->si;
int i;
for (i = 0; i < num_cur_tch; i++) {
cyttsp5_get_touch(pd, tch, si->xy_data +
(i * si->desc.tch_record_size));
/* Check for proximity event */
if (tch->abs[CY_TCH_O] == CY_OBJ_PROXIMITY) {
if (tch->abs[CY_TCH_E] == CY_EV_TOUCHDOWN)
cyttsp5_report_proximity(pd, true);
else if (tch->abs[CY_TCH_E] == CY_EV_LIFTOFF)
cyttsp5_report_proximity(pd, false);
break;
}
}
}
/* read xy_data for all current touches */
static int cyttsp5_xy_worker(struct cyttsp5_proximity_data *pd)
{
struct device *dev = pd->dev;
struct cyttsp5_sysinfo *si = pd->si;
struct cyttsp5_touch tch;
u8 num_cur_tch;
cyttsp5_get_touch_hdr(pd, &tch, si->xy_mode + 3);
num_cur_tch = tch.hdr[CY_TCH_NUM];
if (num_cur_tch > si->sensing_conf_data.max_tch) {
dev_err(dev, "%s: Num touch err detected (n=%d)\n",
__func__, num_cur_tch);
num_cur_tch = si->sensing_conf_data.max_tch;
}
if (tch.hdr[CY_TCH_LO])
dev_dbg(dev, "%s: Large area detected\n", __func__);
/* extract xy_data for all currently reported touches */
dev_vdbg(dev, "%s: extract data num_cur_rec=%d\n", __func__,
num_cur_tch);
if (num_cur_tch)
cyttsp5_get_proximity_touch(pd, &tch, num_cur_tch);
else
cyttsp5_report_proximity(pd, false);
return 0;
}
static int cyttsp5_proximity_attention(struct device *dev)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
int rc = 0;
if (pd->si->xy_mode[2] != pd->si->desc.tch_report_id)
return 0;
mutex_lock(&pd->prox_lock);
rc = cyttsp5_xy_worker(pd);
mutex_unlock(&pd->prox_lock);
if (rc < 0)
dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
return rc;
}
static int cyttsp5_startup_attention(struct device *dev)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
mutex_lock(&pd->prox_lock);
cyttsp5_report_proximity(pd, false);
mutex_unlock(&pd->prox_lock);
return 0;
}
static int _cyttsp5_set_proximity_via_touchmode_enabled(
struct cyttsp5_proximity_data *pd, bool enable)
{
struct device *dev = pd->dev;
u32 touchmode_enabled;
int rc;
rc = cyttsp5_request_nonhid_get_param(dev, 0,
CY_RAM_ID_TOUCHMODE_ENABLED, &touchmode_enabled);
if (rc)
return rc;
if (enable)
touchmode_enabled |= 0x80;
else
touchmode_enabled &= 0x7F;
rc = cyttsp5_request_nonhid_set_param(dev, 0,
CY_RAM_ID_TOUCHMODE_ENABLED, touchmode_enabled,
CY_RAM_ID_TOUCHMODE_ENABLED_SIZE);
return rc;
}
static int _cyttsp5_set_proximity_via_proximity_enable(
struct cyttsp5_proximity_data *pd, bool enable)
{
struct device *dev = pd->dev;
u32 proximity_enable;
int rc;
rc = cyttsp5_request_nonhid_get_param(dev, 0,
CY_RAM_ID_PROXIMITY_ENABLE, &proximity_enable);
if (rc)
return rc;
if (enable)
proximity_enable |= 0x01;
else
proximity_enable &= 0xFE;
rc = cyttsp5_request_nonhid_set_param(dev, 0,
CY_RAM_ID_PROXIMITY_ENABLE, proximity_enable,
CY_RAM_ID_PROXIMITY_ENABLE_SIZE);
return rc;
}
static int _cyttsp5_set_proximity(struct cyttsp5_proximity_data *pd,
bool enable)
{
if (!IS_PIP_VER_GE(pd->si, 1, 4))
return _cyttsp5_set_proximity_via_touchmode_enabled(pd,
enable);
return _cyttsp5_set_proximity_via_proximity_enable(pd, enable);
}
static int _cyttsp5_proximity_enable(struct cyttsp5_proximity_data *pd)
{
struct device *dev = pd->dev;
int rc = 0;
pm_runtime_get_sync(dev);
rc = cyttsp5_request_exclusive(dev,
CYTTSP5_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT);
if (rc < 0) {
dev_err(dev, "%s: Error on request exclusive r=%d\n",
__func__, rc);
goto exit;
}
rc = _cyttsp5_set_proximity(pd, true);
if (rc < 0) {
dev_err(dev, "%s: Error on request enable proximity scantype r=%d\n",
__func__, rc);
goto exit_release;
}
dev_vdbg(dev, "%s: setup subscriptions\n", __func__);
/* set up touch call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_PROXIMITY_NAME,
cyttsp5_proximity_attention, CY_MODE_OPERATIONAL);
/* set up startup call back */
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_PROXIMITY_NAME, cyttsp5_startup_attention, 0);
exit_release:
cyttsp5_release_exclusive(dev);
exit:
return rc;
}
static int _cyttsp5_proximity_disable(struct cyttsp5_proximity_data *pd,
bool force)
{
struct device *dev = pd->dev;
int rc = 0;
rc = cyttsp5_request_exclusive(dev,
CYTTSP5_PROXIMITY_REQUEST_EXCLUSIVE_TIMEOUT);
if (rc < 0) {
dev_err(dev, "%s: Error on request exclusive r=%d\n",
__func__, rc);
goto exit;
}
rc = _cyttsp5_set_proximity(pd, false);
if (rc < 0) {
dev_err(dev, "%s: Error on request disable proximity scan r=%d\n",
__func__, rc);
goto exit_release;
}
exit_release:
cyttsp5_release_exclusive(dev);
exit:
if (!rc || force) {
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_IRQ,
CYTTSP5_PROXIMITY_NAME, cyttsp5_proximity_attention,
CY_MODE_OPERATIONAL);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_PROXIMITY_NAME, cyttsp5_startup_attention, 0);
}
pm_runtime_put(dev);
return rc;
}
static ssize_t cyttsp5_proximity_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
int val = 0;
mutex_lock(&pd->sysfs_lock);
val = pd->enable_count;
mutex_unlock(&pd->sysfs_lock);
return scnprintf(buf, CY_MAX_PRBUF_SIZE, "%d\n", val);
}
static ssize_t cyttsp5_proximity_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
unsigned long value;
int rc;
rc = kstrtoul(buf, 10, &value);
if (rc < 0 || (value != 0 && value != 1)) {
dev_err(dev, "%s: Invalid value\n", __func__);
return -EINVAL;
}
mutex_lock(&pd->sysfs_lock);
if (value) {
if (pd->enable_count++) {
dev_vdbg(dev, "%s: '%s' already enabled\n", __func__,
pd->input->name);
} else {
rc = _cyttsp5_proximity_enable(pd);
if (rc)
pd->enable_count--;
}
} else {
if (--pd->enable_count) {
if (pd->enable_count < 0) {
dev_err(dev, "%s: '%s' unbalanced disable\n",
__func__, pd->input->name);
pd->enable_count = 0;
}
} else {
rc = _cyttsp5_proximity_disable(pd, false);
if (rc)
pd->enable_count++;
}
}
mutex_unlock(&pd->sysfs_lock);
if (rc)
return rc;
return size;
}
static DEVICE_ATTR(prox_enable, S_IRUSR | S_IWUSR,
cyttsp5_proximity_enable_show,
cyttsp5_proximity_enable_store);
static int cyttsp5_setup_input_device_and_sysfs(struct device *dev)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
int signal = CY_IGNORE_VALUE;
int i;
int rc;
rc = device_create_file(dev, &dev_attr_prox_enable);
if (rc) {
dev_err(dev, "%s: Error, could not create enable\n",
__func__);
goto exit;
}
dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
__set_bit(EV_ABS, pd->input->evbit);
/* set event signal capabilities */
for (i = 0; i < NUM_SIGNALS(pd->pdata->frmwrk); i++) {
signal = PARAM_SIGNAL(pd->pdata->frmwrk, i);
if (signal != CY_IGNORE_VALUE) {
input_set_abs_params(pd->input, signal,
PARAM_MIN(pd->pdata->frmwrk, i),
PARAM_MAX(pd->pdata->frmwrk, i),
PARAM_FUZZ(pd->pdata->frmwrk, i),
PARAM_FLAT(pd->pdata->frmwrk, i));
}
}
rc = input_register_device(pd->input);
if (rc) {
dev_err(dev, "%s: Error, failed register input device r=%d\n",
__func__, rc);
goto unregister_enable;
}
pd->input_device_registered = true;
return rc;
unregister_enable:
device_remove_file(dev, &dev_attr_prox_enable);
exit:
return rc;
}
static int cyttsp5_setup_input_attention(struct device *dev)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
int rc;
pd->si = _cyttsp5_request_sysinfo(dev);
if (!pd->si)
return -EINVAL;
rc = cyttsp5_setup_input_device_and_sysfs(dev);
if (!rc)
rc = _cyttsp5_set_proximity(pd, false);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_PROXIMITY_NAME, cyttsp5_setup_input_attention, 0);
return rc;
}
int cyttsp5_proximity_probe(struct device *dev)
{
struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
struct cyttsp5_proximity_data *pd = &cd->pd;
struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
struct cyttsp5_proximity_platform_data *prox_pdata;
int rc = 0;
if (!pdata || !pdata->prox_pdata) {
dev_err(dev, "%s: Missing platform data\n", __func__);
rc = -ENODEV;
goto error_no_pdata;
}
prox_pdata = pdata->prox_pdata;
mutex_init(&pd->prox_lock);
mutex_init(&pd->sysfs_lock);
pd->dev = dev;
pd->pdata = prox_pdata;
/* Create the input device and register it. */
dev_vdbg(dev, "%s: Create the input device and register it\n",
__func__);
pd->input = input_allocate_device();
if (!pd->input) {
dev_err(dev, "%s: Error, failed to allocate input device\n",
__func__);
rc = -ENODEV;
goto error_alloc_failed;
}
if (pd->pdata->inp_dev_name)
pd->input->name = pd->pdata->inp_dev_name;
else
pd->input->name = CYTTSP5_PROXIMITY_NAME;
scnprintf(pd->phys, sizeof(pd->phys), "%s/input%d", dev_name(dev),
cd->phys_num++);
pd->input->phys = pd->phys;
pd->input->dev.parent = pd->dev;
input_set_drvdata(pd->input, pd);
/* get sysinfo */
pd->si = _cyttsp5_request_sysinfo(dev);
if (pd->si) {
rc = cyttsp5_setup_input_device_and_sysfs(dev);
if (rc)
goto error_init_input;
rc = _cyttsp5_set_proximity(pd, false);
} else {
dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
__func__, pd->si);
_cyttsp5_subscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_PROXIMITY_NAME, cyttsp5_setup_input_attention,
0);
}
return 0;
error_init_input:
input_free_device(pd->input);
error_alloc_failed:
error_no_pdata:
dev_err(dev, "%s failed.\n", __func__);
return rc;
}
int cyttsp5_proximity_release(struct device *dev)
{
struct cyttsp5_proximity_data *pd = get_prox_data(dev);
if (pd->input_device_registered) {
/* Disable proximity sensing */
mutex_lock(&pd->sysfs_lock);
if (pd->enable_count)
_cyttsp5_proximity_disable(pd, true);
mutex_unlock(&pd->sysfs_lock);
device_remove_file(dev, &dev_attr_prox_enable);
input_unregister_device(pd->input);
} else {
input_free_device(pd->input);
_cyttsp5_unsubscribe_attention(dev, CY_ATTEN_STARTUP,
CYTTSP5_PROXIMITY_NAME, cyttsp5_setup_input_attention,
0);
}
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,254 @@
/*
* cyttsp5_spi.c
* Parade TrueTouch(TM) Standard Product V5 SPI Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include "cyttsp5_regs.h"
#include <linux/spi/spi.h>
#include <linux/version.h>
#define CY_SPI_WR_OP 0x00 /* r/~w */
#define CY_SPI_RD_OP 0x01
#define CY_SPI_BITS_PER_WORD 8
#define CY_SPI_SYNC_ACK 0x62
#define CY_SPI_CMD_BYTES 0
#define CY_SPI_DATA_SIZE (2 * 256)
#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
static void cyttsp5_spi_add_rw_msg(struct spi_message *msg,
struct spi_transfer *xfer, u8 *w_header, u8 *r_header, u8 op)
{
xfer->tx_buf = w_header;
xfer->rx_buf = r_header;
w_header[0] = op;
xfer->len = 1;
spi_message_add_tail(xfer, msg);
}
static int cyttsp5_spi_xfer(struct device *dev, u8 op, u8 *buf, int length)
{
struct spi_device *spi = to_spi_device(dev);
struct spi_message msg;
struct spi_transfer xfer[2];
u8 w_header[2];
u8 r_header[2];
int rc;
memset(xfer, 0, sizeof(xfer));
spi_message_init(&msg);
cyttsp5_spi_add_rw_msg(&msg, &xfer[0], w_header, r_header, op);
switch (op) {
case CY_SPI_RD_OP:
xfer[1].rx_buf = buf;
xfer[1].len = length;
spi_message_add_tail(&xfer[1], &msg);
break;
case CY_SPI_WR_OP:
xfer[1].tx_buf = buf;
xfer[1].len = length;
spi_message_add_tail(&xfer[1], &msg);
break;
default:
rc = -EIO;
goto exit;
}
rc = spi_sync(spi, &msg);
exit:
if (rc < 0)
dev_vdbg(dev, "%s: spi_sync() error %d\n", __func__, rc);
if (r_header[0] != CY_SPI_SYNC_ACK)
return -EIO;
return rc;
}
static int cyttsp5_spi_read_default(struct device *dev, void *buf, int size)
{
if (!buf || !size)
return 0;
return cyttsp5_spi_xfer(dev, CY_SPI_RD_OP, buf, size);
}
static int cyttsp5_spi_read_default_nosize(struct device *dev, u8 *buf, u32 max)
{
u32 size;
int rc;
if (!buf)
return 0;
rc = cyttsp5_spi_xfer(dev, CY_SPI_RD_OP, buf, 2);
if (rc < 0)
return rc;
size = get_unaligned_le16(&buf[0]);
if (!size)
return rc;
if (size > max)
return -EINVAL;
return cyttsp5_spi_read_default(dev, buf, size);
}
static int cyttsp5_spi_write_read_specific(struct device *dev, u8 write_len,
u8 *write_buf, u8 *read_buf)
{
int rc;
rc = cyttsp5_spi_xfer(dev, CY_SPI_WR_OP, write_buf, write_len);
if (rc < 0)
return rc;
if (read_buf)
rc = cyttsp5_spi_read_default_nosize(dev, read_buf,
CY_SPI_DATA_SIZE);
return rc;
}
static struct cyttsp5_bus_ops cyttsp5_spi_bus_ops = {
.bustype = BUS_SPI,
.read_default = cyttsp5_spi_read_default,
.read_default_nosize = cyttsp5_spi_read_default_nosize,
.write_read_specific = cyttsp5_spi_write_read_specific,
};
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
static const struct of_device_id cyttsp5_spi_of_match[] = {
{ .compatible = "cy,cyttsp5_spi_adapter", },
{ }
};
MODULE_DEVICE_TABLE(of, cyttsp5_spi_of_match);
#endif
static int cyttsp5_spi_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
const struct of_device_id *match;
#endif
int rc;
/* Set up SPI*/
spi->bits_per_word = CY_SPI_BITS_PER_WORD;
spi->mode = SPI_MODE_0;
rc = spi_setup(spi);
if (rc < 0) {
dev_err(dev, "%s: SPI setup error %d\n", __func__, rc);
return rc;
}
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(cyttsp5_spi_of_match), dev);
if (match) {
rc = cyttsp5_devtree_create_and_get_pdata(dev);
if (rc < 0)
return rc;
}
#endif
rc = cyttsp5_probe(&cyttsp5_spi_bus_ops, &spi->dev, spi->irq,
CY_SPI_DATA_BUF_SIZE);
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
if (rc && match)
cyttsp5_devtree_clean_pdata(dev);
#endif
return rc;
}
static int cyttsp5_spi_remove(struct spi_device *spi)
{
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
struct device *dev = &spi->dev;
const struct of_device_id *match;
#endif
struct cyttsp5_core_data *cd = dev_get_drvdata(&spi->dev);
cyttsp5_release(cd);
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
match = of_match_device(of_match_ptr(cyttsp5_spi_of_match), dev);
if (match)
cyttsp5_devtree_clean_pdata(dev);
#endif
return 0;
}
static const struct spi_device_id cyttsp5_spi_id[] = {
{ CYTTSP5_SPI_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, cyttsp5_spi_id);
static struct spi_driver cyttsp5_spi_driver = {
.driver = {
.name = CYTTSP5_SPI_NAME,
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &cyttsp5_pm_ops,
#ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICETREE_SUPPORT
.of_match_table = cyttsp5_spi_of_match,
#endif
},
.probe = cyttsp5_spi_probe,
.remove = (cyttsp5_spi_remove),
.id_table = cyttsp5_spi_id,
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
module_spi_driver(cyttsp5_spi_driver);
#else
static int __init cyttsp5_spi_init(void)
{
int err = spi_register_driver(&cyttsp5_spi_driver);
pr_info("%s: Parade TTSP SPI Driver (Built %s) rc=%d\n",
__func__, CY_DRIVER_VERSION, err);
return err;
}
module_init(cyttsp5_spi_init);
static void __exit cyttsp5_spi_exit(void)
{
spi_unregister_driver(&cyttsp5_spi_driver);
}
module_exit(cyttsp5_spi_exit);
#endif
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product SPI Driver");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

View file

@ -0,0 +1,442 @@
/*
* cyttsp5_test_device_access_api.c
* Parade TrueTouch(TM) Standard Product V5 Device Access API test module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright (C) 2015 Parade Technologies
* Copyright (C) 2012-2015 Cypress Semiconductor
*
* 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*
*/
#include <linux/module.h>
#include <linux/cyttsp5_device_access-api.h>
#include <asm/unaligned.h>
#define BUFFER_SIZE 256
#define COMMAND_GET_SYSTEM_INFO 2
#define COMMAND_SUSPEND_SCANNING 3
#define COMMAND_RESUME_SCANNING 4
#define COMMAND_GET_PARAMETER 5
#define COMMAND_SET_PARAMETER 6
#define PARAMETER_ACTIVE_DISTANCE_2 0x0B
struct tt_output_report {
__le16 reg_address;
__le16 length;
u8 report_id;
u8 reserved;
u8 command;
u8 parameters[0];
} __packed;
struct tt_input_report {
__le16 length;
u8 report_id;
u8 reserved;
u8 command;
u8 return_data[0];
} __packed;
static int prepare_tt_output_report(struct tt_output_report *out,
u16 length, u8 command)
{
put_unaligned_le16(0x04, &out->reg_address);
put_unaligned_le16(5 + length, &out->length);
out->report_id = 0x2f;
out->reserved = 0x00;
out->command = command;
return 7 + length;
}
static int check_and_parse_tt_input_report(struct tt_input_report *in,
u16 *length, u8 *command)
{
if (in->report_id != 0x1f)
return -EINVAL;
*length = get_unaligned_le16(&in->length);
*command = in->command & 0x7f;
return 0;
}
static int prepare_get_system_info_report(u8 *buf)
{
struct tt_output_report *out = (struct tt_output_report *)buf;
return prepare_tt_output_report(out, 0, COMMAND_GET_SYSTEM_INFO);
}
static int check_get_system_info_response(u8 *buf, u16 read_length)
{
struct tt_input_report *in = (struct tt_input_report *)buf;
u16 length = 0;
u8 command = 0;
if (read_length != 51)
return -EINVAL;
if (check_and_parse_tt_input_report(in, &length, &command)
|| command != COMMAND_GET_SYSTEM_INFO
|| length != 51)
return -EINVAL;
pr_info("PIP Major Version: %d\n", in->return_data[0]);
pr_info("PIP Minor Version: %d\n", in->return_data[1]);
pr_info("Touch Firmware Product Id: %d\n",
get_unaligned_le16(&in->return_data[2]));
pr_info("Touch Firmware Major Version: %d\n", in->return_data[4]);
pr_info("Touch Firmware Minor Version: %d\n", in->return_data[5]);
pr_info("Touch Firmware Internal Revision Control Number: %d\n",
get_unaligned_le32(&in->return_data[6]));
pr_info("Customer Specified Firmware/Configuration Version: %d\n",
get_unaligned_le16(&in->return_data[10]));
pr_info("Bootloader Major Version: %d\n", in->return_data[12]);
pr_info("Bootloader Minor Version: %d\n", in->return_data[13]);
pr_info("Family ID: 0x%02x\n", in->return_data[14]);
pr_info("Revision ID: 0x%02x\n", in->return_data[15]);
pr_info("Silicon ID: 0x%02x\n",
get_unaligned_le16(&in->return_data[16]));
pr_info("Parade Manufacturing ID[0]: 0x%02x\n", in->return_data[18]);
pr_info("Parade Manufacturing ID[1]: 0x%02x\n", in->return_data[19]);
pr_info("Parade Manufacturing ID[2]: 0x%02x\n", in->return_data[20]);
pr_info("Parade Manufacturing ID[3]: 0x%02x\n", in->return_data[21]);
pr_info("Parade Manufacturing ID[4]: 0x%02x\n", in->return_data[22]);
pr_info("Parade Manufacturing ID[5]: 0x%02x\n", in->return_data[23]);
pr_info("Parade Manufacturing ID[6]: 0x%02x\n", in->return_data[24]);
pr_info("Parade Manufacturing ID[7]: 0x%02x\n", in->return_data[25]);
pr_info("POST Result Code: 0x%02x\n",
get_unaligned_le16(&in->return_data[26]));
pr_info("Number of X Electrodes: %d\n", in->return_data[28]);
pr_info("Number of Y Electrodes: %d\n", in->return_data[29]);
pr_info("Panel X Axis Length: %d\n",
get_unaligned_le16(&in->return_data[30]));
pr_info("Panel Y Axis Length: %d\n",
get_unaligned_le16(&in->return_data[32]));
pr_info("Panel X Axis Resolution: %d\n",
get_unaligned_le16(&in->return_data[34]));
pr_info("Panel Y Axis Resolution: %d\n",
get_unaligned_le16(&in->return_data[36]));
pr_info("Panel Pressure Resolution: %d\n",
get_unaligned_le16(&in->return_data[38]));
pr_info("X_ORG: %d\n", in->return_data[40]);
pr_info("Y_ORG: %d\n", in->return_data[41]);
pr_info("Panel ID: %d\n", in->return_data[42]);
pr_info("Buttons: 0x%02x\n", in->return_data[43]);
pr_info("BAL SELF MC: 0x%02x\n", in->return_data[44]);
pr_info("Max Number of Touch Records per Refresh Cycle: %d\n",
in->return_data[45]);
return 0;
}
static int prepare_get_parameter_report(u8 *buf, u8 parameter_id)
{
struct tt_output_report *out = (struct tt_output_report *)buf;
out->parameters[0] = parameter_id;
return prepare_tt_output_report(out, 1, COMMAND_GET_PARAMETER);
}
static int check_get_parameter_response(u8 *buf, u16 read_length,
u32 *parameter_value)
{
struct tt_input_report *in = (struct tt_input_report *)buf;
u16 length = 0;
u8 command = 0;
u32 param_value = 0;
u8 param_id;
u8 param_size = 0;
if (read_length != 8 && read_length != 9 && read_length != 11)
return -EINVAL;
if (check_and_parse_tt_input_report(in, &length, &command)
|| command != COMMAND_GET_PARAMETER
|| (length != 8 && length != 9 && length != 11))
return -EINVAL;
param_id = in->return_data[0];
param_size = in->return_data[1];
if (param_size == 1)
param_value = in->return_data[2];
else if (param_size == 2)
param_value = get_unaligned_le16(&in->return_data[2]);
else if (param_size == 4)
param_value = get_unaligned_le32(&in->return_data[2]);
else
return -EINVAL;
pr_info("%s: Parameter ID: 0x%02x Value: 0x%02x\n",
__func__, param_id, param_value);
if (parameter_value)
*parameter_value = param_value;
return 0;
}
static int prepare_set_parameter_report(u8 *buf, u8 parameter_id,
u8 parameter_size, u32 parameter_value)
{
struct tt_output_report *out = (struct tt_output_report *)buf;
out->parameters[0] = parameter_id;
out->parameters[1] = parameter_size;
if (parameter_size == 1)
out->parameters[2] = (u8)parameter_value;
else if (parameter_size == 2)
put_unaligned_le16(parameter_value, &out->parameters[2]);
else if (parameter_size == 4)
put_unaligned_le32(parameter_value, &out->parameters[2]);
else
return -EINVAL;
return prepare_tt_output_report(out, 2 + parameter_size,
COMMAND_SET_PARAMETER);
}
static int check_set_parameter_response(u8 *buf, u16 read_length)
{
struct tt_input_report *in = (struct tt_input_report *)buf;
u16 length = 0;
u8 command = 0;
u8 param_id;
u8 param_size = 0;
if (read_length != 7)
return -EINVAL;
if (check_and_parse_tt_input_report(in, &length, &command)
|| command != COMMAND_SET_PARAMETER
|| length != 7)
return -EINVAL;
param_id = in->return_data[0];
param_size = in->return_data[1];
pr_info("%s: Parameter ID: 0x%02x Size: 0x%02x\n",
__func__, param_id, param_size);
return 0;
}
static int prepare_suspend_scanning_report(u8 *buf)
{
struct tt_output_report *out = (struct tt_output_report *)buf;
return prepare_tt_output_report(out, 0, COMMAND_SUSPEND_SCANNING);
}
static int check_suspend_scanning_response(u8 *buf, u16 read_length)
{
struct tt_input_report *in = (struct tt_input_report *)buf;
u16 length = 0;
u8 command = 0;
if (read_length != 5)
return -EINVAL;
if (check_and_parse_tt_input_report(in, &length, &command)
|| command != COMMAND_SUSPEND_SCANNING
|| length != 5)
return -EINVAL;
return 0;
}
static int prepare_resume_scanning_report(u8 *buf)
{
struct tt_output_report *out = (struct tt_output_report *)buf;
return prepare_tt_output_report(out, 0, COMMAND_RESUME_SCANNING);
}
static int check_resume_scanning_response(u8 *buf, u16 read_length)
{
struct tt_input_report *in = (struct tt_input_report *)buf;
u16 length = 0;
u8 command = 0;
if (read_length != 5)
return -EINVAL;
if (check_and_parse_tt_input_report(in, &length, &command)
|| command != COMMAND_RESUME_SCANNING
|| length != 5)
return -EINVAL;
return 0;
}
void cyttsp5_user_command_async_cont(const char *core_name,
u16 read_len, u8 *read_buf, u16 write_len, u8 *write_buf,
u16 actual_read_length, int rc)
{
if (rc) {
pr_err("%s: suspend scan fails\n", __func__);
goto exit;
}
rc = check_suspend_scanning_response(read_buf, actual_read_length);
if (rc) {
pr_err("%s: check suspend scanning response fails\n", __func__);
goto exit;
}
pr_info("%s: suspend scanning succeeds\n", __func__);
exit:
return;
}
/* Read and write buffers */
static u8 write_buf[BUFFER_SIZE];
static u8 read_buf[BUFFER_SIZE];
static uint active_distance;
module_param(active_distance, uint, 0);
static int __init cyttsp5_test_device_access_api_init(void)
{
u32 initial_active_distance;
u16 actual_read_len;
int write_len;
int rc;
pr_info("%s: Enter\n", __func__);
/* CASE 1: Run get system information */
write_len = prepare_get_system_info_report(write_buf);
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
read_buf, write_len, write_buf,
&actual_read_len);
if (rc)
goto exit;
rc = check_get_system_info_response(read_buf, actual_read_len);
if (rc)
goto exit;
/* CASE 2: Run get parameter (Active distance) */
write_len = prepare_get_parameter_report(write_buf,
PARAMETER_ACTIVE_DISTANCE_2);
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
read_buf, write_len, write_buf,
&actual_read_len);
if (rc)
goto exit;
rc = check_get_parameter_response(read_buf, actual_read_len,
&initial_active_distance);
if (rc)
goto exit;
pr_info("%s: Initial Active Distance: %d\n",
__func__, initial_active_distance);
/* CASE 3: Run set parameter (Active distance) */
write_len = prepare_set_parameter_report(write_buf,
PARAMETER_ACTIVE_DISTANCE_2, 1,
active_distance);
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
read_buf, write_len, write_buf,
&actual_read_len);
if (rc)
goto exit;
rc = check_set_parameter_response(read_buf, actual_read_len);
if (rc)
goto exit;
pr_info("%s: Active Distance set to %d\n", __func__, active_distance);
/* CASE 4: Run get parameter (Active distance) */
write_len = prepare_get_parameter_report(write_buf,
PARAMETER_ACTIVE_DISTANCE_2);
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
read_buf, write_len, write_buf,
&actual_read_len);
if (rc)
goto exit;
rc = check_get_parameter_response(read_buf, actual_read_len,
&active_distance);
if (rc)
goto exit;
pr_info("%s: New Active Distance: %d\n", __func__, active_distance);
/* CASE 5: Run suspend scanning asynchronously */
write_len = prepare_suspend_scanning_report(write_buf);
preempt_disable();
rc = cyttsp5_device_access_user_command_async(NULL,
sizeof(read_buf), read_buf, write_len, write_buf,
cyttsp5_user_command_async_cont);
preempt_enable();
if (rc)
goto exit;
exit:
return rc;
}
module_init(cyttsp5_test_device_access_api_init);
static void __exit cyttsp5_test_device_access_api_exit(void)
{
u16 actual_read_len;
int write_len;
int rc;
/* CASE 6: Run resume scanning */
write_len = prepare_resume_scanning_report(write_buf);
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
read_buf, write_len, write_buf,
&actual_read_len);
if (rc)
goto exit;
rc = check_resume_scanning_response(read_buf, actual_read_len);
if (rc)
goto exit;
pr_info("%s: resume scanning succeeds\n", __func__);
exit:
return;
}
module_exit(cyttsp5_test_device_access_api_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Device Access Driver API Tester");
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");

View file

@ -0,0 +1,990 @@
#
# Touchscreen driver configuration
#
menuconfig INPUT_TOUCHSCREEN
bool "Touchscreens"
help
Say Y here, and a list of supported touchscreens will be displayed.
This option doesn't affect the kernel.
If unsure, say Y.
if INPUT_TOUCHSCREEN
config OF_TOUCHSCREEN
def_tristate INPUT
depends on INPUT && OF
config TOUCHSCREEN_88PM860X
tristate "Marvell 88PM860x touchscreen"
depends on MFD_88PM860X
help
Say Y here if you have a 88PM860x PMIC and want to enable
support for the built-in touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called 88pm860x-ts.
config TOUCHSCREEN_ADS7846
tristate "ADS7846/TSC2046/AD7873 and AD(S)7843 based touchscreens"
depends on SPI_MASTER
depends on HWMON = n || HWMON
help
Say Y here if you have a touchscreen interface using the
ADS7846/TSC2046/AD7873 or ADS7843/AD7843 controller,
and your board-specific setup code includes that in its
table of SPI devices.
If HWMON is selected, and the driver is told the reference voltage
on your board, you will also get hwmon interfaces for the voltage
(and on ads7846/tsc2046/ad7873, temperature) sensors of this chip.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ads7846.
config TOUCHSCREEN_AD7877
tristate "AD7877 based touchscreens"
depends on SPI_MASTER
help
Say Y here if you have a touchscreen interface using the
AD7877 controller, and your board-specific initialization
code includes that in its table of SPI devices.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7877.
config TOUCHSCREEN_AD7879
tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface"
help
Say Y here if you want to support a touchscreen interface using
the AD7879-1/AD7889-1 controller.
You should select a bus connection too.
To compile this driver as a module, choose M here: the
module will be called ad7879.
config TOUCHSCREEN_AD7879_I2C
tristate "support I2C bus connection"
depends on TOUCHSCREEN_AD7879 && I2C
help
Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called ad7879-i2c.
config TOUCHSCREEN_AD7879_SPI
tristate "support SPI bus connection"
depends on TOUCHSCREEN_AD7879 && SPI_MASTER
help
Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
module will be called ad7879-spi.
config TOUCHSCREEN_AR1021_I2C
tristate "Microchip AR1021 i2c touchscreen"
depends on I2C && OF
help
Say Y here if you have the Microchip AR1021 touchscreen controller
chip in your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called ar1021_i2c.
config TOUCHSCREEN_ATMEL_MXT
tristate "Atmel mXT I2C Touchscreen"
depends on I2C
select FW_LOADER
help
Say Y here if you have Atmel mXT series I2C touchscreen,
such as AT42QT602240/ATMXT224, connected to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called atmel_mxt_ts.
config TOUCHSCREEN_AUO_PIXCIR
tristate "AUO in-cell touchscreen using Pixcir ICs"
depends on I2C
depends on GPIOLIB
help
Say Y here if you have a AUO display with in-cell touchscreen
using Pixcir ICs.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called auo-pixcir-ts.
config TOUCHSCREEN_BU21013
tristate "BU21013 based touch panel controllers"
depends on I2C
help
Say Y here if you have a bu21013 touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called bu21013_ts.
config TOUCHSCREEN_CY8CTMG110
tristate "cy8ctmg110 touchscreen"
depends on I2C
depends on GPIOLIB
help
Say Y here if you have a cy8ctmg110 capacitive touchscreen on
an AAVA device.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cy8ctmg110_ts.
config TOUCHSCREEN_CYTTSP_CORE
tristate "Cypress TTSP touchscreen"
help
Say Y here if you have a touchscreen using controller from
the Cypress TrueTouch(tm) Standard Product family connected
to your system. You will also need to select appropriate
bus connection below.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called cyttsp_core.
config TOUCHSCREEN_CYTTSP_I2C
tristate "support I2C bus connection"
depends on TOUCHSCREEN_CYTTSP_CORE && I2C
help
Say Y here if the touchscreen is connected via I2C bus.
To compile this driver as a module, choose M here: the
module will be called cyttsp_i2c.
config TOUCHSCREEN_CYTTSP_SPI
tristate "support SPI bus connection"
depends on TOUCHSCREEN_CYTTSP_CORE && SPI_MASTER
help
Say Y here if the touchscreen is connected via SPI bus.
To compile this driver as a module, choose M here: the
module will be called cyttsp_spi.
config TOUCHSCREEN_CYTTSP4_CORE
tristate "Cypress TrueTouch Gen4 Touchscreen Driver"
help
Core driver for Cypress TrueTouch(tm) Standard Product
Generation4 touchscreen controllers.
Say Y here if you have a Cypress Gen4 touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_CYTTSP4_I2C
tristate "support I2C bus connection"
depends on TOUCHSCREEN_CYTTSP4_CORE && I2C
help
Say Y here if the touchscreen is connected via I2C bus.
To compile this driver as a module, choose M here: the
module will be called cyttsp4_i2c.
config TOUCHSCREEN_CYTTSP4_SPI
tristate "support SPI bus connection"
depends on TOUCHSCREEN_CYTTSP4_CORE && SPI_MASTER
help
Say Y here if the touchscreen is connected via SPI bus.
To compile this driver as a module, choose M here: the
module will be called cyttsp4_spi.
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
default y
help
Say Y here to enable the support for the touchscreen found
on Dialog Semiconductor DA9034 PMIC.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called da9034-ts.
config TOUCHSCREEN_DA9052
tristate "Dialog DA9052/DA9053 TSI"
depends on PMIC_DA9052
help
Say Y here to support the touchscreen found on Dialog Semiconductor
DA9052-BC and DA9053-AA/Bx PMICs.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called da9052_tsi.
config TOUCHSCREEN_DYNAPRO
tristate "Dynapro serial touchscreen"
select SERIO
help
Say Y here if you have a Dynapro serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called dynapro.
config TOUCHSCREEN_HAMPSHIRE
tristate "Hampshire serial touchscreen"
select SERIO
help
Say Y here if you have a Hampshire serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called hampshire.
config TOUCHSCREEN_EETI
tristate "EETI touchscreen panel support"
depends on I2C
help
Say Y here to enable support for I2C connected EETI touch panels.
To compile this driver as a module, choose M here: the
module will be called eeti_ts.
config TOUCHSCREEN_EGALAX
tristate "EETI eGalax multi-touch panel support"
depends on I2C && OF
help
Say Y here to enable support for I2C connected EETI
eGalax multi-touch panels.
To compile this driver as a module, choose M here: the
module will be called egalax_ts.
config TOUCHSCREEN_FUJITSU
tristate "Fujitsu serial touchscreen"
select SERIO
help
Say Y here if you have the Fujitsu touchscreen (such as one
installed in Lifebook P series laptop) connected to your
system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called fujitsu-ts.
config TOUCHSCREEN_ILI210X
tristate "Ilitek ILI210X based touchscreen"
depends on I2C
help
Say Y here if you have a ILI210X based touchscreen
controller. This driver supports models ILI2102,
ILI2102s, ILI2103, ILI2103s and ILI2105.
Such kind of chipsets can be found in Amazon Kindle Fire
touchscreens.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called ili210x.
config TOUCHSCREEN_S3C2410
tristate "Samsung S3C2410/generic touchscreen input driver"
depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
select S3C_ADC
help
Say Y here if you have the s3c2410 touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called s3c2410_ts.
config TOUCHSCREEN_GUNZE
tristate "Gunze AHL-51S touchscreen"
select SERIO
help
Say Y here if you have the Gunze AHL-51 touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called gunze.
config TOUCHSCREEN_ELO
tristate "Elo serial touchscreens"
select SERIO
help
Say Y here if you have an Elo serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called elo.
config TOUCHSCREEN_WACOM_W8001
tristate "Wacom W8001 penabled serial touchscreen"
select SERIO
help
Say Y here if you have an Wacom W8001 penabled serial touchscreen
connected to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called wacom_w8001.
config TOUCHSCREEN_WACOM_I2C
tristate "Wacom Tablet support (I2C)"
depends on I2C
help
Say Y here if you want to use the I2C version of the Wacom
Pen Tablet.
If unsure, say N.
To compile this driver as a module, choose M here: the module
will be called wacom_i2c.
config TOUCHSCREEN_LPC32XX
tristate "LPC32XX touchscreen controller"
depends on ARCH_LPC32XX
help
Say Y here if you have a LPC32XX device and want
to support the built-in touchscreen.
To compile this driver as a module, choose M here: the
module will be called lpc32xx_ts.
config TOUCHSCREEN_MAX11801
tristate "MAX11801 based touchscreens"
depends on I2C
help
Say Y here if you have a MAX11801 based touchscreen
controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called max11801_ts.
config TOUCHSCREEN_MCS5000
tristate "MELFAS MCS-5000 touchscreen"
depends on I2C
help
Say Y here if you have the MELFAS MCS-5000 touchscreen controller
chip in your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mcs5000_ts.
config TOUCHSCREEN_MMS114
tristate "MELFAS MMS114 touchscreen"
depends on I2C
help
Say Y here if you have the MELFAS MMS114 touchscreen controller
chip in your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mms114.
config TOUCHSCREEN_MMS144
tristate "Melfas MMS144 Touchscreen"
depends on I2C
help
Say Y here if you have Melfas MMS144 series I2C touchscreen,
connected to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mms_ts.
config TOUCHSCREEN_MTOUCH
tristate "MicroTouch serial touchscreens"
select SERIO
help
Say Y here if you have a MicroTouch (3M) serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mtouch.
config TOUCHSCREEN_INEXIO
tristate "iNexio serial touchscreens"
select SERIO
help
Say Y here if you have an iNexio serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called inexio.
config TOUCHSCREEN_INTEL_MID
tristate "Intel MID platform resistive touchscreen"
depends on INTEL_SCU_IPC
help
Say Y here if you have a Intel MID based touchscreen in
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called intel_mid_touch.
config TOUCHSCREEN_MK712
tristate "ICS MicroClock MK712 touchscreen"
help
Say Y here if you have the ICS MicroClock MK712 touchscreen
controller chip in your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mk712.
config TOUCHSCREEN_HP600
tristate "HP Jornada 6xx touchscreen"
depends on SH_HP6XX && SH_ADC
help
Say Y here if you have a HP Jornada 620/660/680/690 and want to
support the built-in touchscreen.
To compile this driver as a module, choose M here: the
module will be called hp680_ts_input.
config TOUCHSCREEN_HP7XX
tristate "HP Jornada 7xx touchscreen"
depends on SA1100_JORNADA720_SSP
help
Say Y here if you have a HP Jornada 710/720/728 and want
to support the built-in touchscreen.
To compile this driver as a module, choose M here: the
module will be called jornada720_ts.
config TOUCHSCREEN_IPAQ_MICRO
tristate "HP iPAQ Atmel Micro ASIC touchscreen"
depends on MFD_IPAQ_MICRO
help
Say Y here to enable support for the touchscreen attached to
the Atmel Micro peripheral controller on iPAQ h3100/h3600/h3700
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called ipaq-micro-ts.
config TOUCHSCREEN_HTCPEN
tristate "HTC Shift X9500 touchscreen"
depends on ISA
help
Say Y here if you have an HTC Shift UMPC also known as HTC X9500
Clio / Shangrila and want to support the built-in touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called htcpen.
config TOUCHSCREEN_PENMOUNT
tristate "Penmount serial touchscreen"
select SERIO
help
Say Y here if you have a Penmount serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called penmount.
config TOUCHSCREEN_EDT_FT5X06
tristate "EDT FocalTech FT5x06 I2C Touchscreen support"
depends on I2C
help
Say Y here if you have an EDT "Polytouch" touchscreen based
on the FocalTech FT5x06 family of controllers connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called edt-ft5x06.
config TOUCHSCREEN_MIGOR
tristate "Renesas MIGO-R touchscreen"
depends on SH_MIGOR && I2C
help
Say Y here to enable MIGO-R touchscreen support.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called migor_ts.
config TOUCHSCREEN_TOUCHRIGHT
tristate "Touchright serial touchscreen"
select SERIO
help
Say Y here if you have a Touchright serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called touchright.
config TOUCHSCREEN_TOUCHWIN
tristate "Touchwin serial touchscreen"
select SERIO
help
Say Y here if you have a Touchwin serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called touchwin.
config TOUCHSCREEN_TI_AM335X_TSC
tristate "TI Touchscreen Interface"
depends on MFD_TI_AM335X_TSCADC
help
Say Y here if you have 4/5/8 wire touchscreen controller
to be connected to the ADC controller on your TI AM335x SoC.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called ti_am335x_tsc.
config TOUCHSCREEN_UCB1400
tristate "Philips UCB1400 touchscreen"
depends on AC97_BUS
depends on UCB1400_CORE
help
This enables support for the Philips UCB1400 touchscreen interface.
The UCB1400 is an AC97 audio codec. The touchscreen interface
will be initialized only after the ALSA subsystem has been
brought up and the UCB1400 detected. You therefore have to
configure ALSA support as well (either built-in or modular,
independently of whether this driver is itself built-in or
modular) for this driver to work.
To compile this driver as a module, choose M here: the
module will be called ucb1400_ts.
config TOUCHSCREEN_PIXCIR
tristate "PIXCIR I2C touchscreens"
depends on I2C
help
Say Y here if you have a pixcir i2c touchscreen
controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called pixcir_i2c_ts.
config TOUCHSCREEN_WM831X
tristate "Support for WM831x touchscreen controllers"
depends on MFD_WM831X
help
This enables support for the touchscreen controller on the WM831x
series of PMICs.
To compile this driver as a module, choose M here: the
module will be called wm831x-ts.
config TOUCHSCREEN_WM97XX
tristate "Support for WM97xx AC97 touchscreen controllers"
depends on AC97_BUS
help
Say Y here if you have a Wolfson Microelectronics WM97xx
touchscreen connected to your system. Note that this option
only enables core driver, you will also need to select
support for appropriate chip below.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called wm97xx-ts.
config TOUCHSCREEN_WM9705
bool "WM9705 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
default y
help
Say Y here to enable support for the Wolfson Microelectronics
WM9705 touchscreen controller.
config TOUCHSCREEN_WM9712
bool "WM9712 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
default y
help
Say Y here to enable support for the Wolfson Microelectronics
WM9712 touchscreen controller.
config TOUCHSCREEN_WM9713
bool "WM9713 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
default y
help
Say Y here to enable support for the Wolfson Microelectronics
WM9713 touchscreen controller.
config TOUCHSCREEN_WM97XX_ATMEL
tristate "WM97xx Atmel accelerated touch"
depends on TOUCHSCREEN_WM97XX && AVR32
help
Say Y here for support for streaming mode with WM97xx touchscreens
on Atmel AT91 or AVR32 systems with an AC97C module.
Be aware that this will use channel B in the controller for
streaming data, this must not conflict with other AC97C drivers.
If unsure, say N.
To compile this driver as a module, choose M here: the module will
be called atmel-wm97xx.
config TOUCHSCREEN_WM97XX_MAINSTONE
tristate "WM97xx Mainstone/Palm accelerated touch"
depends on TOUCHSCREEN_WM97XX && ARCH_PXA
help
Say Y here for support for streaming mode with WM97xx touchscreens
on Mainstone, Palm Tungsten T5, TX and LifeDrive systems.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mainstone-wm97xx.
config TOUCHSCREEN_WM97XX_ZYLONITE
tristate "Zylonite accelerated touch"
depends on TOUCHSCREEN_WM97XX && MACH_ZYLONITE
select TOUCHSCREEN_WM9713
help
Say Y here for support for streaming mode with the touchscreen
on Zylonite systems.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called zylonite-wm97xx.
config TOUCHSCREEN_USB_COMPOSITE
tristate "USB Touchscreen Driver"
depends on USB_ARCH_HAS_HCD
select USB
help
USB Touchscreen driver for:
- eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
- PanJit TouchSet USB
- 3M MicroTouch USB (EX II series)
- ITM
- some other eTurboTouch
- Gunze AHL61
- DMC TSC-10/25
- IRTOUCHSYSTEMS/UNITOP
- IdealTEK URTC1000
- GoTop Super_Q2/GogoPen/PenPower tablets
- JASTEC USB Touch Controller/DigiTech DTR-02U
- Zytronic controllers
- Elo TouchSystems 2700 IntelliTouch
- EasyTouch USB Touch Controller from Data Modul
- e2i (Mimo monitors)
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
To compile this driver as a module, choose M here: the
module will be called usbtouchscreen.
config TOUCHSCREEN_MC13783
tristate "Freescale MC13783 touchscreen input driver"
depends on MFD_MC13XXX
help
Say Y here if you have an Freescale MC13783 PMIC on your
board and want to use its touchscreen
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mc13783_ts.
config TOUCHSCREEN_USB_EGALAX
default y
bool "eGalax, eTurboTouch CT-410/510/700 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_PANJIT
default y
bool "PanJit device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_3M
default y
bool "3M/Microtouch EX II series device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ITM
default y
bool "ITM device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ETURBO
default y
bool "eTurboTouch (non-eGalax compatible) device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GUNZE
default y
bool "Gunze AHL61 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_DMC_TSC10
default y
bool "DMC TSC-10/25 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_IRTOUCH
default y
bool "IRTOUCHSYSTEMS/UNITOP device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_IDEALTEK
default y
bool "IdealTEK URTC1000 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GENERAL_TOUCH
default y
bool "GeneralTouch Touchscreen device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GOTOP
default y
bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_JASTEC
default y
bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ELO
default y
bool "Elo TouchSystems 2700 IntelliTouch controller device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_E2I
default y
bool "e2i Touchscreen controller (e.g. from Mimo 740)" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ZYTRONIC
default y
bool "Zytronic controller" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ETT_TC45USB
default y
bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_NEXIO
default y
bool "NEXIO/iNexio device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_EASYTOUCH
default y
bool "EasyTouch USB Touch controller device support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
help
Say Y here if you have an EasyTouch USB Touch controller.
If unsure, say N.
config TOUCHSCREEN_TOUCHIT213
tristate "Sahara TouchIT-213 touchscreen"
select SERIO
help
Say Y here if you have a Sahara TouchIT-213 Tablet PC.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called touchit213.
config TOUCHSCREEN_TSC_SERIO
tristate "TSC-10/25/40 serial touchscreen support"
select SERIO
help
Say Y here if you have a TSC-10, 25 or 40 serial touchscreen connected
to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tsc40.
config TOUCHSCREEN_TSC2005
tristate "TSC2005 based touchscreens"
depends on SPI_MASTER
help
Say Y here if you have a TSC2005 based touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tsc2005.
config TOUCHSCREEN_TSC2007
tristate "TSC2007 based touchscreens"
depends on I2C
help
Say Y here if you have a TSC2007 based touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tsc2007.
config TOUCHSCREEN_W90X900
tristate "W90P910 touchscreen driver"
depends on ARCH_W90X900
help
Say Y here if you have a W90P910 based touchscreen.
To compile this driver as a module, choose M here: the
module will be called w90p910_ts.
config TOUCHSCREEN_PCAP
tristate "Motorola PCAP touchscreen"
depends on EZX_PCAP
help
Say Y here if you have a Motorola EZX telephone and
want to enable support for the built-in touchscreen.
To compile this driver as a module, choose M here: the
module will be called pcap_ts.
config TOUCHSCREEN_ST1232
tristate "Sitronix ST1232 touchscreen controllers"
depends on I2C
help
Say Y here if you want to support Sitronix ST1232
touchscreen controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called st1232_ts.
config TOUCHSCREEN_STMPE
tristate "STMicroelectronics STMPE touchscreens"
depends on MFD_STMPE
help
Say Y here if you want support for STMicroelectronics
STMPE touchscreen controllers.
To compile this driver as a module, choose M here: the
module will be called stmpe-ts.
config TOUCHSCREEN_SUN4I
tristate "Allwinner sun4i resistive touchscreen controller support"
depends on ARCH_SUNXI || COMPILE_TEST
depends on HWMON
help
This selects support for the resistive touchscreen controller
found on Allwinner sunxi SoCs.
To compile this driver as a module, choose M here: the
module will be called sun4i-ts.
config TOUCHSCREEN_SUR40
tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen"
depends on USB
select INPUT_POLLDEV
help
Say Y here if you want support for the Samsung SUR40 touchscreen
(also known as Microsoft Surface 2.0 or Microsoft PixelSense).
To compile this driver as a module, choose M here: the
module will be called sur40.
config TOUCHSCREEN_TPS6507X
tristate "TPS6507x based touchscreens"
depends on I2C
select INPUT_POLLDEV
help
Say Y here if you have a TPS6507x based touchscreen
controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tps6507x_ts.
config TOUCHSCREEN_ZFORCE
tristate "Neonode zForce infrared touchscreens"
depends on I2C
depends on GPIOLIB
help
Say Y here if you have a touchscreen using the zforce
infraread technology from Neonode.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called zforce_ts.
config TOUCHSCREEN_MXT540E
tristate "Atmel MXT540E Touchscreen Interface"
depends on I2C
help
Say Y here if you want support for atmel_MXT540E touchscreen controllers.
To compile this driver as a module, choose M here: the
module will be called mxt540e.
source "drivers/input/touchscreen/imagis_30xxc/Kconfig"
source "drivers/input/touchscreen/Cyttsp5_525a/Kconfig"
source "drivers/input/touchscreen/melfas_mms400/Kconfig"
source "drivers/input/touchscreen/stm/Kconfig"
source "drivers/input/touchscreen/synaptics_td4x00/Kconfig"
endif

View file

@ -0,0 +1,88 @@
#
# Makefile for the touchscreen drivers.
#
# Each configuration option enables a list of files.
wm97xx-ts-y := wm97xx-core.o
obj-$(CONFIG_OF_TOUCHSCREEN) += of_touchscreen.o
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_CORE) += cyttsp4_core.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_I2C) += cyttsp4_i2c.o cyttsp_i2c_common.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI) += cyttsp4_spi.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
obj-$(CONFIG_TOUCHSCREEN_MMS114) += mms114.o
obj-$(CONFIG_TOUCHSCREEN_MMS144) += mms144.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO) += ipaq-micro-ts.o
obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C) += wacom_i2c.o
obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
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_TOUCHSCREEN_ZFORCE) += zforce_ts.o
obj-$(CONFIG_TOUCHSCREEN_MXT540E) += mxt540e.o
obj-$(CONFIG_TOUCHSCREEN_IST3038C) += imagis_30xxc/
obj-$(CONFIG_TOUCHSCREEN_FTS) += stm/
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MMS449) += melfas_mms400/
obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5) += Cyttsp5_525a/
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_TD4X00) += synaptics_td4x00/

View file

@ -0,0 +1,860 @@
/*
* Copyright (C) 2006-2008 Michael Hennerich, Analog Devices Inc.
*
* Description: AD7877 based touchscreen, sensor (ADCs), DAC and GPIO driver
* Based on: ads7846.c
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* History:
* Copyright (c) 2005 David Brownell
* Copyright (c) 2006 Nokia Corporation
* Various changes: Imre Deak <imre.deak@nokia.com>
*
* Using code from:
* - corgi_ts.c
* Copyright (C) 2004-2005 Richard Purdie
* - omap_ts.[hc], ads7846.h, ts_osk.c
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
*/
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/ad7877.h>
#include <linux/module.h>
#include <asm/irq.h>
#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(100)
#define MAX_SPI_FREQ_HZ 20000000
#define MAX_12BIT ((1<<12)-1)
#define AD7877_REG_ZEROS 0
#define AD7877_REG_CTRL1 1
#define AD7877_REG_CTRL2 2
#define AD7877_REG_ALERT 3
#define AD7877_REG_AUX1HIGH 4
#define AD7877_REG_AUX1LOW 5
#define AD7877_REG_BAT1HIGH 6
#define AD7877_REG_BAT1LOW 7
#define AD7877_REG_BAT2HIGH 8
#define AD7877_REG_BAT2LOW 9
#define AD7877_REG_TEMP1HIGH 10
#define AD7877_REG_TEMP1LOW 11
#define AD7877_REG_SEQ0 12
#define AD7877_REG_SEQ1 13
#define AD7877_REG_DAC 14
#define AD7877_REG_NONE1 15
#define AD7877_REG_EXTWRITE 15
#define AD7877_REG_XPLUS 16
#define AD7877_REG_YPLUS 17
#define AD7877_REG_Z2 18
#define AD7877_REG_aux1 19
#define AD7877_REG_aux2 20
#define AD7877_REG_aux3 21
#define AD7877_REG_bat1 22
#define AD7877_REG_bat2 23
#define AD7877_REG_temp1 24
#define AD7877_REG_temp2 25
#define AD7877_REG_Z1 26
#define AD7877_REG_GPIOCTRL1 27
#define AD7877_REG_GPIOCTRL2 28
#define AD7877_REG_GPIODATA 29
#define AD7877_REG_NONE2 30
#define AD7877_REG_NONE3 31
#define AD7877_SEQ_YPLUS_BIT (1<<11)
#define AD7877_SEQ_XPLUS_BIT (1<<10)
#define AD7877_SEQ_Z2_BIT (1<<9)
#define AD7877_SEQ_AUX1_BIT (1<<8)
#define AD7877_SEQ_AUX2_BIT (1<<7)
#define AD7877_SEQ_AUX3_BIT (1<<6)
#define AD7877_SEQ_BAT1_BIT (1<<5)
#define AD7877_SEQ_BAT2_BIT (1<<4)
#define AD7877_SEQ_TEMP1_BIT (1<<3)
#define AD7877_SEQ_TEMP2_BIT (1<<2)
#define AD7877_SEQ_Z1_BIT (1<<1)
enum {
AD7877_SEQ_YPOS = 0,
AD7877_SEQ_XPOS = 1,
AD7877_SEQ_Z2 = 2,
AD7877_SEQ_AUX1 = 3,
AD7877_SEQ_AUX2 = 4,
AD7877_SEQ_AUX3 = 5,
AD7877_SEQ_BAT1 = 6,
AD7877_SEQ_BAT2 = 7,
AD7877_SEQ_TEMP1 = 8,
AD7877_SEQ_TEMP2 = 9,
AD7877_SEQ_Z1 = 10,
AD7877_NR_SENSE = 11,
};
/* DAC Register Default RANGE 0 to Vcc, Volatge Mode, DAC On */
#define AD7877_DAC_CONF 0x1
/* If gpio3 is set AUX3/GPIO3 acts as GPIO Output */
#define AD7877_EXTW_GPIO_3_CONF 0x1C4
#define AD7877_EXTW_GPIO_DATA 0x200
/* Control REG 2 */
#define AD7877_TMR(x) ((x & 0x3) << 0)
#define AD7877_REF(x) ((x & 0x1) << 2)
#define AD7877_POL(x) ((x & 0x1) << 3)
#define AD7877_FCD(x) ((x & 0x3) << 4)
#define AD7877_PM(x) ((x & 0x3) << 6)
#define AD7877_ACQ(x) ((x & 0x3) << 8)
#define AD7877_AVG(x) ((x & 0x3) << 10)
/* Control REG 1 */
#define AD7877_SER (1 << 11) /* non-differential */
#define AD7877_DFR (0 << 11) /* differential */
#define AD7877_MODE_NOC (0) /* Do not convert */
#define AD7877_MODE_SCC (1) /* Single channel conversion */
#define AD7877_MODE_SEQ0 (2) /* Sequence 0 in Slave Mode */
#define AD7877_MODE_SEQ1 (3) /* Sequence 1 in Master Mode */
#define AD7877_CHANADD(x) ((x&0xF)<<7)
#define AD7877_READADD(x) ((x)<<2)
#define AD7877_WRITEADD(x) ((x)<<12)
#define AD7877_READ_CHAN(x) (AD7877_WRITEADD(AD7877_REG_CTRL1) | AD7877_SER | \
AD7877_MODE_SCC | AD7877_CHANADD(AD7877_REG_ ## x) | \
AD7877_READADD(AD7877_REG_ ## x))
#define AD7877_MM_SEQUENCE (AD7877_SEQ_YPLUS_BIT | AD7877_SEQ_XPLUS_BIT | \
AD7877_SEQ_Z2_BIT | AD7877_SEQ_Z1_BIT)
/*
* Non-touchscreen sensors only use single-ended conversions.
*/
struct ser_req {
u16 reset;
u16 ref_on;
u16 command;
struct spi_message msg;
struct spi_transfer xfer[6];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
u16 sample ____cacheline_aligned;
};
struct ad7877 {
struct input_dev *input;
char phys[32];
struct spi_device *spi;
u16 model;
u16 vref_delay_usecs;
u16 x_plate_ohms;
u16 pressure_max;
u16 cmd_crtl1;
u16 cmd_crtl2;
u16 cmd_dummy;
u16 dac;
u8 stopacq_polarity;
u8 first_conversion_delay;
u8 acquisition_time;
u8 averaging;
u8 pen_down_acc_interval;
struct spi_transfer xfer[AD7877_NR_SENSE + 2];
struct spi_message msg;
struct mutex mutex;
bool disabled; /* P: mutex */
bool gpio3; /* P: mutex */
bool gpio4; /* P: mutex */
spinlock_t lock;
struct timer_list timer; /* P: lock */
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
u16 conversion_data[AD7877_NR_SENSE] ____cacheline_aligned;
};
static bool gpio3;
module_param(gpio3, bool, 0);
MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
static int ad7877_read(struct spi_device *spi, u16 reg)
{
struct ser_req *req;
int status, ret;
req = kzalloc(sizeof *req, GFP_KERNEL);
if (!req)
return -ENOMEM;
spi_message_init(&req->msg);
req->command = (u16) (AD7877_WRITEADD(AD7877_REG_CTRL1) |
AD7877_READADD(reg));
req->xfer[0].tx_buf = &req->command;
req->xfer[0].len = 2;
req->xfer[0].cs_change = 1;
req->xfer[1].rx_buf = &req->sample;
req->xfer[1].len = 2;
spi_message_add_tail(&req->xfer[0], &req->msg);
spi_message_add_tail(&req->xfer[1], &req->msg);
status = spi_sync(spi, &req->msg);
ret = status ? : req->sample;
kfree(req);
return ret;
}
static int ad7877_write(struct spi_device *spi, u16 reg, u16 val)
{
struct ser_req *req;
int status;
req = kzalloc(sizeof *req, GFP_KERNEL);
if (!req)
return -ENOMEM;
spi_message_init(&req->msg);
req->command = (u16) (AD7877_WRITEADD(reg) | (val & MAX_12BIT));
req->xfer[0].tx_buf = &req->command;
req->xfer[0].len = 2;
spi_message_add_tail(&req->xfer[0], &req->msg);
status = spi_sync(spi, &req->msg);
kfree(req);
return status;
}
static int ad7877_read_adc(struct spi_device *spi, unsigned command)
{
struct ad7877 *ts = spi_get_drvdata(spi);
struct ser_req *req;
int status;
int sample;
int i;
req = kzalloc(sizeof *req, GFP_KERNEL);
if (!req)
return -ENOMEM;
spi_message_init(&req->msg);
/* activate reference, so it has time to settle; */
req->ref_on = AD7877_WRITEADD(AD7877_REG_CTRL2) |
AD7877_POL(ts->stopacq_polarity) |
AD7877_AVG(0) | AD7877_PM(2) | AD7877_TMR(0) |
AD7877_ACQ(ts->acquisition_time) | AD7877_FCD(0);
req->reset = AD7877_WRITEADD(AD7877_REG_CTRL1) | AD7877_MODE_NOC;
req->command = (u16) command;
req->xfer[0].tx_buf = &req->reset;
req->xfer[0].len = 2;
req->xfer[0].cs_change = 1;
req->xfer[1].tx_buf = &req->ref_on;
req->xfer[1].len = 2;
req->xfer[1].delay_usecs = ts->vref_delay_usecs;
req->xfer[1].cs_change = 1;
req->xfer[2].tx_buf = &req->command;
req->xfer[2].len = 2;
req->xfer[2].delay_usecs = ts->vref_delay_usecs;
req->xfer[2].cs_change = 1;
req->xfer[3].rx_buf = &req->sample;
req->xfer[3].len = 2;
req->xfer[3].cs_change = 1;
req->xfer[4].tx_buf = &ts->cmd_crtl2; /*REF OFF*/
req->xfer[4].len = 2;
req->xfer[4].cs_change = 1;
req->xfer[5].tx_buf = &ts->cmd_crtl1; /*DEFAULT*/
req->xfer[5].len = 2;
/* group all the transfers together, so we can't interfere with
* reading touchscreen state; disable penirq while sampling
*/
for (i = 0; i < 6; i++)
spi_message_add_tail(&req->xfer[i], &req->msg);
status = spi_sync(spi, &req->msg);
sample = req->sample;
kfree(req);
return status ? : sample;
}
static int ad7877_process_data(struct ad7877 *ts)
{
struct input_dev *input_dev = ts->input;
unsigned Rt;
u16 x, y, z1, z2;
x = ts->conversion_data[AD7877_SEQ_XPOS] & MAX_12BIT;
y = ts->conversion_data[AD7877_SEQ_YPOS] & MAX_12BIT;
z1 = ts->conversion_data[AD7877_SEQ_Z1] & MAX_12BIT;
z2 = ts->conversion_data[AD7877_SEQ_Z2] & MAX_12BIT;
/*
* The samples processed here are already preprocessed by the AD7877.
* The preprocessing function consists of an averaging filter.
* The combination of 'first conversion delay' and averaging provides a robust solution,
* discarding the spurious noise in the signal and keeping only the data of interest.
* The size of the averaging filter is programmable. (dev.platform_data, see linux/spi/ad7877.h)
* Other user-programmable conversion controls include variable acquisition time,
* and first conversion delay. Up to 16 averages can be taken per conversion.
*/
if (likely(x && z1)) {
/* compute touch pressure resistance using equation #1 */
Rt = (z2 - z1) * x * ts->x_plate_ohms;
Rt /= z1;
Rt = (Rt + 2047) >> 12;
/*
* Sample found inconsistent, pressure is beyond
* the maximum. Don't report it to user space.
*/
if (Rt > ts->pressure_max)
return -EINVAL;
if (!timer_pending(&ts->timer))
input_report_key(input_dev, BTN_TOUCH, 1);
input_report_abs(input_dev, ABS_X, x);
input_report_abs(input_dev, ABS_Y, y);
input_report_abs(input_dev, ABS_PRESSURE, Rt);
input_sync(input_dev);
return 0;
}
return -EINVAL;
}
static inline void ad7877_ts_event_release(struct ad7877 *ts)
{
struct input_dev *input_dev = ts->input;
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
}
static void ad7877_timer(unsigned long handle)
{
struct ad7877 *ts = (void *)handle;
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
ad7877_ts_event_release(ts);
spin_unlock_irqrestore(&ts->lock, flags);
}
static irqreturn_t ad7877_irq(int irq, void *handle)
{
struct ad7877 *ts = handle;
unsigned long flags;
int error;
error = spi_sync(ts->spi, &ts->msg);
if (error) {
dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
goto out;
}
spin_lock_irqsave(&ts->lock, flags);
error = ad7877_process_data(ts);
if (!error)
mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
spin_unlock_irqrestore(&ts->lock, flags);
out:
return IRQ_HANDLED;
}
static void ad7877_disable(struct ad7877 *ts)
{
mutex_lock(&ts->mutex);
if (!ts->disabled) {
ts->disabled = true;
disable_irq(ts->spi->irq);
if (del_timer_sync(&ts->timer))
ad7877_ts_event_release(ts);
}
/*
* We know the chip's in lowpower mode since we always
* leave it that way after every request
*/
mutex_unlock(&ts->mutex);
}
static void ad7877_enable(struct ad7877 *ts)
{
mutex_lock(&ts->mutex);
if (ts->disabled) {
ts->disabled = false;
enable_irq(ts->spi->irq);
}
mutex_unlock(&ts->mutex);
}
#define SHOW(name) static ssize_t \
name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct ad7877 *ts = dev_get_drvdata(dev); \
ssize_t v = ad7877_read_adc(ts->spi, \
AD7877_READ_CHAN(name)); \
if (v < 0) \
return v; \
return sprintf(buf, "%u\n", (unsigned) v); \
} \
static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
SHOW(aux1)
SHOW(aux2)
SHOW(aux3)
SHOW(bat1)
SHOW(bat2)
SHOW(temp1)
SHOW(temp2)
static ssize_t ad7877_disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->disabled);
}
static ssize_t ad7877_disable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned int val;
int error;
error = kstrtouint(buf, 10, &val);
if (error)
return error;
if (val)
ad7877_disable(ts);
else
ad7877_enable(ts);
return count;
}
static DEVICE_ATTR(disable, 0664, ad7877_disable_show, ad7877_disable_store);
static ssize_t ad7877_dac_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->dac);
}
static ssize_t ad7877_dac_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned int val;
int error;
error = kstrtouint(buf, 10, &val);
if (error)
return error;
mutex_lock(&ts->mutex);
ts->dac = val & 0xFF;
ad7877_write(ts->spi, AD7877_REG_DAC, (ts->dac << 4) | AD7877_DAC_CONF);
mutex_unlock(&ts->mutex);
return count;
}
static DEVICE_ATTR(dac, 0664, ad7877_dac_show, ad7877_dac_store);
static ssize_t ad7877_gpio3_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->gpio3);
}
static ssize_t ad7877_gpio3_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned int val;
int error;
error = kstrtouint(buf, 10, &val);
if (error)
return error;
mutex_lock(&ts->mutex);
ts->gpio3 = !!val;
ad7877_write(ts->spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_DATA |
(ts->gpio4 << 4) | (ts->gpio3 << 5));
mutex_unlock(&ts->mutex);
return count;
}
static DEVICE_ATTR(gpio3, 0664, ad7877_gpio3_show, ad7877_gpio3_store);
static ssize_t ad7877_gpio4_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ad7877 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->gpio4);
}
static ssize_t ad7877_gpio4_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ad7877 *ts = dev_get_drvdata(dev);
unsigned int val;
int error;
error = kstrtouint(buf, 10, &val);
if (error)
return error;
mutex_lock(&ts->mutex);
ts->gpio4 = !!val;
ad7877_write(ts->spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_DATA |
(ts->gpio4 << 4) | (ts->gpio3 << 5));
mutex_unlock(&ts->mutex);
return count;
}
static DEVICE_ATTR(gpio4, 0664, ad7877_gpio4_show, ad7877_gpio4_store);
static struct attribute *ad7877_attributes[] = {
&dev_attr_temp1.attr,
&dev_attr_temp2.attr,
&dev_attr_aux1.attr,
&dev_attr_aux2.attr,
&dev_attr_aux3.attr,
&dev_attr_bat1.attr,
&dev_attr_bat2.attr,
&dev_attr_disable.attr,
&dev_attr_dac.attr,
&dev_attr_gpio3.attr,
&dev_attr_gpio4.attr,
NULL
};
static umode_t ad7877_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
umode_t mode = attr->mode;
if (attr == &dev_attr_aux3.attr) {
if (gpio3)
mode = 0;
} else if (attr == &dev_attr_gpio3.attr) {
if (!gpio3)
mode = 0;
}
return mode;
}
static const struct attribute_group ad7877_attr_group = {
.is_visible = ad7877_attr_is_visible,
.attrs = ad7877_attributes,
};
static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
{
struct spi_message *m;
int i;
ts->cmd_crtl2 = AD7877_WRITEADD(AD7877_REG_CTRL2) |
AD7877_POL(ts->stopacq_polarity) |
AD7877_AVG(ts->averaging) | AD7877_PM(1) |
AD7877_TMR(ts->pen_down_acc_interval) |
AD7877_ACQ(ts->acquisition_time) |
AD7877_FCD(ts->first_conversion_delay);
ad7877_write(spi, AD7877_REG_CTRL2, ts->cmd_crtl2);
ts->cmd_crtl1 = AD7877_WRITEADD(AD7877_REG_CTRL1) |
AD7877_READADD(AD7877_REG_XPLUS-1) |
AD7877_MODE_SEQ1 | AD7877_DFR;
ad7877_write(spi, AD7877_REG_CTRL1, ts->cmd_crtl1);
ts->cmd_dummy = 0;
m = &ts->msg;
spi_message_init(m);
m->context = ts;
ts->xfer[0].tx_buf = &ts->cmd_crtl1;
ts->xfer[0].len = 2;
ts->xfer[0].cs_change = 1;
spi_message_add_tail(&ts->xfer[0], m);
ts->xfer[1].tx_buf = &ts->cmd_dummy; /* Send ZERO */
ts->xfer[1].len = 2;
ts->xfer[1].cs_change = 1;
spi_message_add_tail(&ts->xfer[1], m);
for (i = 0; i < AD7877_NR_SENSE; i++) {
ts->xfer[i + 2].rx_buf = &ts->conversion_data[AD7877_SEQ_YPOS + i];
ts->xfer[i + 2].len = 2;
if (i < (AD7877_NR_SENSE - 1))
ts->xfer[i + 2].cs_change = 1;
spi_message_add_tail(&ts->xfer[i + 2], m);
}
}
static int ad7877_probe(struct spi_device *spi)
{
struct ad7877 *ts;
struct input_dev *input_dev;
struct ad7877_platform_data *pdata = dev_get_platdata(&spi->dev);
int err;
u16 verify;
if (!spi->irq) {
dev_dbg(&spi->dev, "no IRQ?\n");
return -ENODEV;
}
if (!pdata) {
dev_dbg(&spi->dev, "no platform data?\n");
return -ENODEV;
}
/* don't exceed max specified SPI CLK frequency */
if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
dev_dbg(&spi->dev, "SPI CLK %d Hz?\n",spi->max_speed_hz);
return -EINVAL;
}
spi->bits_per_word = 16;
err = spi_setup(spi);
if (err) {
dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n");
return err;
}
ts = kzalloc(sizeof(struct ad7877), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
spi_set_drvdata(spi, ts);
ts->spi = spi;
ts->input = input_dev;
setup_timer(&ts->timer, ad7877_timer, (unsigned long) ts);
mutex_init(&ts->mutex);
spin_lock_init(&ts->lock);
ts->model = pdata->model ? : 7877;
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
ts->pressure_max = pdata->pressure_max ? : ~0;
ts->stopacq_polarity = pdata->stopacq_polarity;
ts->first_conversion_delay = pdata->first_conversion_delay;
ts->acquisition_time = pdata->acquisition_time;
ts->averaging = pdata->averaging;
ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
input_dev->name = "AD7877 Touchscreen";
input_dev->phys = ts->phys;
input_dev->dev.parent = &spi->dev;
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(ABS_X, input_dev->absbit);
__set_bit(ABS_Y, input_dev->absbit);
__set_bit(ABS_PRESSURE, input_dev->absbit);
input_set_abs_params(input_dev, ABS_X,
pdata->x_min ? : 0,
pdata->x_max ? : MAX_12BIT,
0, 0);
input_set_abs_params(input_dev, ABS_Y,
pdata->y_min ? : 0,
pdata->y_max ? : MAX_12BIT,
0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE,
pdata->pressure_min, pdata->pressure_max, 0, 0);
ad7877_write(spi, AD7877_REG_SEQ1, AD7877_MM_SEQUENCE);
verify = ad7877_read(spi, AD7877_REG_SEQ1);
if (verify != AD7877_MM_SEQUENCE){
dev_err(&spi->dev, "%s: Failed to probe %s\n",
dev_name(&spi->dev), input_dev->name);
err = -ENODEV;
goto err_free_mem;
}
if (gpio3)
ad7877_write(spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_3_CONF);
ad7877_setup_ts_def_msg(spi, ts);
/* Request AD7877 /DAV GPIO interrupt */
err = request_threaded_irq(spi->irq, NULL, ad7877_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
spi->dev.driver->name, ts);
if (err) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
goto err_free_mem;
}
err = sysfs_create_group(&spi->dev.kobj, &ad7877_attr_group);
if (err)
goto err_free_irq;
err = input_register_device(input_dev);
if (err)
goto err_remove_attr_group;
return 0;
err_remove_attr_group:
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
err_free_irq:
free_irq(spi->irq, ts);
err_free_mem:
input_free_device(input_dev);
kfree(ts);
return err;
}
static int ad7877_remove(struct spi_device *spi)
{
struct ad7877 *ts = spi_get_drvdata(spi);
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
ad7877_disable(ts);
free_irq(ts->spi->irq, ts);
input_unregister_device(ts->input);
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int ad7877_suspend(struct device *dev)
{
struct ad7877 *ts = dev_get_drvdata(dev);
ad7877_disable(ts);
return 0;
}
static int ad7877_resume(struct device *dev)
{
struct ad7877 *ts = dev_get_drvdata(dev);
ad7877_enable(ts);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume);
static struct spi_driver ad7877_driver = {
.driver = {
.name = "ad7877",
.owner = THIS_MODULE,
.pm = &ad7877_pm,
},
.probe = ad7877_probe,
.remove = ad7877_remove,
};
module_spi_driver(ad7877_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("AD7877 touchscreen Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:ad7877");

View file

@ -0,0 +1,109 @@
/*
* AD7879-1/AD7889-1 touchscreen (I2C bus)
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_I2C */
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pm.h>
#include "ad7879.h"
#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
/* All registers are word-sized.
* AD7879 uses a high-byte first convention.
*/
static int ad7879_i2c_read(struct device *dev, u8 reg)
{
struct i2c_client *client = to_i2c_client(dev);
return i2c_smbus_read_word_swapped(client, reg);
}
static int ad7879_i2c_multi_read(struct device *dev,
u8 first_reg, u8 count, u16 *buf)
{
struct i2c_client *client = to_i2c_client(dev);
u8 idx;
i2c_smbus_read_i2c_block_data(client, first_reg, count * 2, (u8 *)buf);
for (idx = 0; idx < count; ++idx)
buf[idx] = swab16(buf[idx]);
return 0;
}
static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val)
{
struct i2c_client *client = to_i2c_client(dev);
return i2c_smbus_write_word_swapped(client, reg, val);
}
static const struct ad7879_bus_ops ad7879_i2c_bus_ops = {
.bustype = BUS_I2C,
.read = ad7879_i2c_read,
.multi_read = ad7879_i2c_multi_read,
.write = ad7879_i2c_write,
};
static int ad7879_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ad7879 *ts;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA)) {
dev_err(&client->dev, "SMBUS Word Data not Supported\n");
return -EIO;
}
ts = ad7879_probe(&client->dev, AD7879_DEVID, client->irq,
&ad7879_i2c_bus_ops);
if (IS_ERR(ts))
return PTR_ERR(ts);
i2c_set_clientdata(client, ts);
return 0;
}
static int ad7879_i2c_remove(struct i2c_client *client)
{
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_remove(ts);
return 0;
}
static const struct i2c_device_id ad7879_id[] = {
{ "ad7879", 0 },
{ "ad7889", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad7879_id);
static struct i2c_driver ad7879_i2c_driver = {
.driver = {
.name = "ad7879",
.owner = THIS_MODULE,
.pm = &ad7879_pm_ops,
},
.probe = ad7879_i2c_probe,
.remove = ad7879_i2c_remove,
.id_table = ad7879_id,
};
module_i2c_driver(ad7879_i2c_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,164 @@
/*
* AD7879/AD7889 touchscreen (SPI bus)
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/input.h> /* BUS_SPI */
#include <linux/pm.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include "ad7879.h"
#define AD7879_DEVID 0x7A /* AD7879/AD7889 */
#define MAX_SPI_FREQ_HZ 5000000
#define AD7879_CMD_MAGIC 0xE000
#define AD7879_CMD_READ (1 << 10)
#define AD7879_CMD(reg) (AD7879_CMD_MAGIC | ((reg) & 0xF))
#define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
#define AD7879_READCMD(reg) (AD7879_CMD(reg) | AD7879_CMD_READ)
/*
* ad7879_read/write are only used for initial setup and for sysfs controls.
* The main traffic is done in ad7879_collect().
*/
static int ad7879_spi_xfer(struct spi_device *spi,
u16 cmd, u8 count, u16 *tx_buf, u16 *rx_buf)
{
struct spi_message msg;
struct spi_transfer *xfers;
void *spi_data;
u16 *command;
u16 *_rx_buf = _rx_buf; /* shut gcc up */
u8 idx;
int ret;
xfers = spi_data = kzalloc(sizeof(*xfers) * (count + 2), GFP_KERNEL);
if (!spi_data)
return -ENOMEM;
spi_message_init(&msg);
command = spi_data;
command[0] = cmd;
if (count == 1) {
/* ad7879_spi_{read,write} gave us buf on stack */
command[1] = *tx_buf;
tx_buf = &command[1];
_rx_buf = rx_buf;
rx_buf = &command[2];
}
++xfers;
xfers[0].tx_buf = command;
xfers[0].len = 2;
spi_message_add_tail(&xfers[0], &msg);
++xfers;
for (idx = 0; idx < count; ++idx) {
if (rx_buf)
xfers[idx].rx_buf = &rx_buf[idx];
if (tx_buf)
xfers[idx].tx_buf = &tx_buf[idx];
xfers[idx].len = 2;
spi_message_add_tail(&xfers[idx], &msg);
}
ret = spi_sync(spi, &msg);
if (count == 1)
_rx_buf[0] = command[2];
kfree(spi_data);
return ret;
}
static int ad7879_spi_multi_read(struct device *dev,
u8 first_reg, u8 count, u16 *buf)
{
struct spi_device *spi = to_spi_device(dev);
return ad7879_spi_xfer(spi, AD7879_READCMD(first_reg), count, NULL, buf);
}
static int ad7879_spi_read(struct device *dev, u8 reg)
{
struct spi_device *spi = to_spi_device(dev);
u16 ret, dummy;
return ad7879_spi_xfer(spi, AD7879_READCMD(reg), 1, &dummy, &ret) ? : ret;
}
static int ad7879_spi_write(struct device *dev, u8 reg, u16 val)
{
struct spi_device *spi = to_spi_device(dev);
u16 dummy;
return ad7879_spi_xfer(spi, AD7879_WRITECMD(reg), 1, &val, &dummy);
}
static const struct ad7879_bus_ops ad7879_spi_bus_ops = {
.bustype = BUS_SPI,
.read = ad7879_spi_read,
.multi_read = ad7879_spi_multi_read,
.write = ad7879_spi_write,
};
static int ad7879_spi_probe(struct spi_device *spi)
{
struct ad7879 *ts;
int err;
/* don't exceed max specified SPI CLK frequency */
if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
return -EINVAL;
}
spi->bits_per_word = 16;
err = spi_setup(spi);
if (err) {
dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n");
return err;
}
ts = ad7879_probe(&spi->dev, AD7879_DEVID, spi->irq, &ad7879_spi_bus_ops);
if (IS_ERR(ts))
return PTR_ERR(ts);
spi_set_drvdata(spi, ts);
return 0;
}
static int ad7879_spi_remove(struct spi_device *spi)
{
struct ad7879 *ts = spi_get_drvdata(spi);
ad7879_remove(ts);
return 0;
}
static struct spi_driver ad7879_spi_driver = {
.driver = {
.name = "ad7879",
.owner = THIS_MODULE,
.pm = &ad7879_pm_ops,
},
.probe = ad7879_spi_probe,
.remove = ad7879_spi_remove,
};
module_spi_driver(ad7879_spi_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:ad7879");

View file

@ -0,0 +1,649 @@
/*
* AD7879/AD7889 based touchscreen and GPIO driver
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*
* History:
* Copyright (c) 2005 David Brownell
* Copyright (c) 2006 Nokia Corporation
* Various changes: Imre Deak <imre.deak@nokia.com>
*
* Using code from:
* - corgi_ts.c
* Copyright (C) 2004-2005 Richard Purdie
* - omap_ts.[hc], ads7846.h, ts_osk.c
* Copyright (C) 2002 MontaVista Software
* Copyright (C) 2004 Texas Instruments
* Copyright (C) 2005 Dirk Behme
* - ad7877.c
* Copyright (C) 2006-2008 Analog Devices Inc.
*/
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/spi/ad7879.h>
#include <linux/module.h>
#include "ad7879.h"
#define AD7879_REG_ZEROS 0
#define AD7879_REG_CTRL1 1
#define AD7879_REG_CTRL2 2
#define AD7879_REG_CTRL3 3
#define AD7879_REG_AUX1HIGH 4
#define AD7879_REG_AUX1LOW 5
#define AD7879_REG_TEMP1HIGH 6
#define AD7879_REG_TEMP1LOW 7
#define AD7879_REG_XPLUS 8
#define AD7879_REG_YPLUS 9
#define AD7879_REG_Z1 10
#define AD7879_REG_Z2 11
#define AD7879_REG_AUXVBAT 12
#define AD7879_REG_TEMP 13
#define AD7879_REG_REVID 14
/* Control REG 1 */
#define AD7879_TMR(x) ((x & 0xFF) << 0)
#define AD7879_ACQ(x) ((x & 0x3) << 8)
#define AD7879_MODE_NOC (0 << 10) /* Do not convert */
#define AD7879_MODE_SCC (1 << 10) /* Single channel conversion */
#define AD7879_MODE_SEQ0 (2 << 10) /* Sequence 0 in Slave Mode */
#define AD7879_MODE_SEQ1 (3 << 10) /* Sequence 1 in Master Mode */
#define AD7879_MODE_INT (1 << 15) /* PENIRQ disabled INT enabled */
/* Control REG 2 */
#define AD7879_FCD(x) ((x & 0x3) << 0)
#define AD7879_RESET (1 << 4)
#define AD7879_MFS(x) ((x & 0x3) << 5)
#define AD7879_AVG(x) ((x & 0x3) << 7)
#define AD7879_SER (1 << 9) /* non-differential */
#define AD7879_DFR (0 << 9) /* differential */
#define AD7879_GPIOPOL (1 << 10)
#define AD7879_GPIODIR (1 << 11)
#define AD7879_GPIO_DATA (1 << 12)
#define AD7879_GPIO_EN (1 << 13)
#define AD7879_PM(x) ((x & 0x3) << 14)
#define AD7879_PM_SHUTDOWN (0)
#define AD7879_PM_DYN (1)
#define AD7879_PM_FULLON (2)
/* Control REG 3 */
#define AD7879_TEMPMASK_BIT (1<<15)
#define AD7879_AUXVBATMASK_BIT (1<<14)
#define AD7879_INTMODE_BIT (1<<13)
#define AD7879_GPIOALERTMASK_BIT (1<<12)
#define AD7879_AUXLOW_BIT (1<<11)
#define AD7879_AUXHIGH_BIT (1<<10)
#define AD7879_TEMPLOW_BIT (1<<9)
#define AD7879_TEMPHIGH_BIT (1<<8)
#define AD7879_YPLUS_BIT (1<<7)
#define AD7879_XPLUS_BIT (1<<6)
#define AD7879_Z1_BIT (1<<5)
#define AD7879_Z2_BIT (1<<4)
#define AD7879_AUX_BIT (1<<3)
#define AD7879_VBAT_BIT (1<<2)
#define AD7879_TEMP_BIT (1<<1)
enum {
AD7879_SEQ_XPOS = 0,
AD7879_SEQ_YPOS = 1,
AD7879_SEQ_Z1 = 2,
AD7879_SEQ_Z2 = 3,
AD7879_NR_SENSE = 4,
};
#define MAX_12BIT ((1<<12)-1)
#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50)
struct ad7879 {
const struct ad7879_bus_ops *bops;
struct device *dev;
struct input_dev *input;
struct timer_list timer;
#ifdef CONFIG_GPIOLIB
struct gpio_chip gc;
struct mutex mutex;
#endif
unsigned int irq;
bool disabled; /* P: input->mutex */
bool suspended; /* P: input->mutex */
bool swap_xy;
u16 conversion_data[AD7879_NR_SENSE];
char phys[32];
u8 first_conversion_delay;
u8 acquisition_time;
u8 averaging;
u8 pen_down_acc_interval;
u8 median;
u16 x_plate_ohms;
u16 pressure_max;
u16 cmd_crtl1;
u16 cmd_crtl2;
u16 cmd_crtl3;
int x;
int y;
int Rt;
};
static int ad7879_read(struct ad7879 *ts, u8 reg)
{
return ts->bops->read(ts->dev, reg);
}
static int ad7879_multi_read(struct ad7879 *ts, u8 first_reg, u8 count, u16 *buf)
{
return ts->bops->multi_read(ts->dev, first_reg, count, buf);
}
static int ad7879_write(struct ad7879 *ts, u8 reg, u16 val)
{
return ts->bops->write(ts->dev, reg, val);
}
static int ad7879_report(struct ad7879 *ts)
{
struct input_dev *input_dev = ts->input;
unsigned Rt;
u16 x, y, z1, z2;
x = ts->conversion_data[AD7879_SEQ_XPOS] & MAX_12BIT;
y = ts->conversion_data[AD7879_SEQ_YPOS] & MAX_12BIT;
z1 = ts->conversion_data[AD7879_SEQ_Z1] & MAX_12BIT;
z2 = ts->conversion_data[AD7879_SEQ_Z2] & MAX_12BIT;
if (ts->swap_xy)
swap(x, y);
/*
* The samples processed here are already preprocessed by the AD7879.
* The preprocessing function consists of a median and an averaging
* filter. The combination of these two techniques provides a robust
* solution, discarding the spurious noise in the signal and keeping
* only the data of interest. The size of both filters is
* programmable. (dev.platform_data, see linux/spi/ad7879.h) Other
* user-programmable conversion controls include variable acquisition
* time, and first conversion delay. Up to 16 averages can be taken
* per conversion.
*/
if (likely(x && z1)) {
/* compute touch pressure resistance using equation #1 */
Rt = (z2 - z1) * x * ts->x_plate_ohms;
Rt /= z1;
Rt = (Rt + 2047) >> 12;
/*
* Sample found inconsistent, pressure is beyond
* the maximum. Don't report it to user space.
*/
if (Rt > ts->pressure_max)
return -EINVAL;
/*
* Note that we delay reporting events by one sample.
* This is done to avoid reporting last sample of the
* touch sequence, which may be incomplete if finger
* leaves the surface before last reading is taken.
*/
if (timer_pending(&ts->timer)) {
/* Touch continues */
input_report_key(input_dev, BTN_TOUCH, 1);
input_report_abs(input_dev, ABS_X, ts->x);
input_report_abs(input_dev, ABS_Y, ts->y);
input_report_abs(input_dev, ABS_PRESSURE, ts->Rt);
input_sync(input_dev);
}
ts->x = x;
ts->y = y;
ts->Rt = Rt;
return 0;
}
return -EINVAL;
}
static void ad7879_ts_event_release(struct ad7879 *ts)
{
struct input_dev *input_dev = ts->input;
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
}
static void ad7879_timer(unsigned long handle)
{
struct ad7879 *ts = (void *)handle;
ad7879_ts_event_release(ts);
}
static irqreturn_t ad7879_irq(int irq, void *handle)
{
struct ad7879 *ts = handle;
ad7879_multi_read(ts, AD7879_REG_XPLUS, AD7879_NR_SENSE, ts->conversion_data);
if (!ad7879_report(ts))
mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
return IRQ_HANDLED;
}
static void __ad7879_enable(struct ad7879 *ts)
{
ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
ad7879_write(ts, AD7879_REG_CTRL3, ts->cmd_crtl3);
ad7879_write(ts, AD7879_REG_CTRL1, ts->cmd_crtl1);
enable_irq(ts->irq);
}
static void __ad7879_disable(struct ad7879 *ts)
{
u16 reg = (ts->cmd_crtl2 & ~AD7879_PM(-1)) |
AD7879_PM(AD7879_PM_SHUTDOWN);
disable_irq(ts->irq);
if (del_timer_sync(&ts->timer))
ad7879_ts_event_release(ts);
ad7879_write(ts, AD7879_REG_CTRL2, reg);
}
static int ad7879_open(struct input_dev *input)
{
struct ad7879 *ts = input_get_drvdata(input);
/* protected by input->mutex */
if (!ts->disabled && !ts->suspended)
__ad7879_enable(ts);
return 0;
}
static void ad7879_close(struct input_dev* input)
{
struct ad7879 *ts = input_get_drvdata(input);
/* protected by input->mutex */
if (!ts->disabled && !ts->suspended)
__ad7879_disable(ts);
}
#ifdef CONFIG_PM_SLEEP
static int ad7879_suspend(struct device *dev)
{
struct ad7879 *ts = dev_get_drvdata(dev);
mutex_lock(&ts->input->mutex);
if (!ts->suspended && !ts->disabled && ts->input->users)
__ad7879_disable(ts);
ts->suspended = true;
mutex_unlock(&ts->input->mutex);
return 0;
}
static int ad7879_resume(struct device *dev)
{
struct ad7879 *ts = dev_get_drvdata(dev);
mutex_lock(&ts->input->mutex);
if (ts->suspended && !ts->disabled && ts->input->users)
__ad7879_enable(ts);
ts->suspended = false;
mutex_unlock(&ts->input->mutex);
return 0;
}
#endif
SIMPLE_DEV_PM_OPS(ad7879_pm_ops, ad7879_suspend, ad7879_resume);
EXPORT_SYMBOL(ad7879_pm_ops);
static void ad7879_toggle(struct ad7879 *ts, bool disable)
{
mutex_lock(&ts->input->mutex);
if (!ts->suspended && ts->input->users != 0) {
if (disable) {
if (ts->disabled)
__ad7879_enable(ts);
} else {
if (!ts->disabled)
__ad7879_disable(ts);
}
}
ts->disabled = disable;
mutex_unlock(&ts->input->mutex);
}
static ssize_t ad7879_disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ad7879 *ts = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ts->disabled);
}
static ssize_t ad7879_disable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ad7879 *ts = dev_get_drvdata(dev);
unsigned int val;
int error;
error = kstrtouint(buf, 10, &val);
if (error)
return error;
ad7879_toggle(ts, val);
return count;
}
static DEVICE_ATTR(disable, 0664, ad7879_disable_show, ad7879_disable_store);
static struct attribute *ad7879_attributes[] = {
&dev_attr_disable.attr,
NULL
};
static const struct attribute_group ad7879_attr_group = {
.attrs = ad7879_attributes,
};
#ifdef CONFIG_GPIOLIB
static int ad7879_gpio_direction_input(struct gpio_chip *chip,
unsigned gpio)
{
struct ad7879 *ts = container_of(chip, struct ad7879, gc);
int err;
mutex_lock(&ts->mutex);
ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL;
err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
return err;
}
static int ad7879_gpio_direction_output(struct gpio_chip *chip,
unsigned gpio, int level)
{
struct ad7879 *ts = container_of(chip, struct ad7879, gc);
int err;
mutex_lock(&ts->mutex);
ts->cmd_crtl2 &= ~AD7879_GPIODIR;
ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIOPOL;
if (level)
ts->cmd_crtl2 |= AD7879_GPIO_DATA;
else
ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
return err;
}
static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
struct ad7879 *ts = container_of(chip, struct ad7879, gc);
u16 val;
mutex_lock(&ts->mutex);
val = ad7879_read(ts, AD7879_REG_CTRL2);
mutex_unlock(&ts->mutex);
return !!(val & AD7879_GPIO_DATA);
}
static void ad7879_gpio_set_value(struct gpio_chip *chip,
unsigned gpio, int value)
{
struct ad7879 *ts = container_of(chip, struct ad7879, gc);
mutex_lock(&ts->mutex);
if (value)
ts->cmd_crtl2 |= AD7879_GPIO_DATA;
else
ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
}
static int ad7879_gpio_add(struct ad7879 *ts,
const struct ad7879_platform_data *pdata)
{
int ret = 0;
mutex_init(&ts->mutex);
if (pdata->gpio_export) {
ts->gc.direction_input = ad7879_gpio_direction_input;
ts->gc.direction_output = ad7879_gpio_direction_output;
ts->gc.get = ad7879_gpio_get_value;
ts->gc.set = ad7879_gpio_set_value;
ts->gc.can_sleep = 1;
ts->gc.base = pdata->gpio_base;
ts->gc.ngpio = 1;
ts->gc.label = "AD7879-GPIO";
ts->gc.owner = THIS_MODULE;
ts->gc.dev = ts->dev;
ret = gpiochip_add(&ts->gc);
if (ret)
dev_err(ts->dev, "failed to register gpio %d\n",
ts->gc.base);
}
return ret;
}
static void ad7879_gpio_remove(struct ad7879 *ts)
{
const struct ad7879_platform_data *pdata = dev_get_platdata(ts->dev);
if (pdata->gpio_export)
gpiochip_remove(&ts->gc);
}
#else
static inline int ad7879_gpio_add(struct ad7879 *ts,
const struct ad7879_platform_data *pdata)
{
return 0;
}
static inline void ad7879_gpio_remove(struct ad7879 *ts)
{
}
#endif
struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
const struct ad7879_bus_ops *bops)
{
struct ad7879_platform_data *pdata = dev_get_platdata(dev);
struct ad7879 *ts;
struct input_dev *input_dev;
int err;
u16 revid;
if (!irq) {
dev_err(dev, "no IRQ?\n");
err = -EINVAL;
goto err_out;
}
if (!pdata) {
dev_err(dev, "no platform data?\n");
err = -EINVAL;
goto err_out;
}
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
ts->bops = bops;
ts->dev = dev;
ts->input = input_dev;
ts->irq = irq;
ts->swap_xy = pdata->swap_xy;
setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
ts->pressure_max = pdata->pressure_max ? : ~0;
ts->first_conversion_delay = pdata->first_conversion_delay;
ts->acquisition_time = pdata->acquisition_time;
ts->averaging = pdata->averaging;
ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
ts->median = pdata->median;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
input_dev->name = "AD7879 Touchscreen";
input_dev->phys = ts->phys;
input_dev->dev.parent = dev;
input_dev->id.bustype = bops->bustype;
input_dev->open = ad7879_open;
input_dev->close = ad7879_close;
input_set_drvdata(input_dev, ts);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(ABS_X, input_dev->absbit);
__set_bit(ABS_Y, input_dev->absbit);
__set_bit(ABS_PRESSURE, input_dev->absbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X,
pdata->x_min ? : 0,
pdata->x_max ? : MAX_12BIT,
0, 0);
input_set_abs_params(input_dev, ABS_Y,
pdata->y_min ? : 0,
pdata->y_max ? : MAX_12BIT,
0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE,
pdata->pressure_min, pdata->pressure_max, 0, 0);
err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET);
if (err < 0) {
dev_err(dev, "Failed to write %s\n", input_dev->name);
goto err_free_mem;
}
revid = ad7879_read(ts, AD7879_REG_REVID);
input_dev->id.product = (revid & 0xff);
input_dev->id.version = revid >> 8;
if (input_dev->id.product != devid) {
dev_err(dev, "Failed to probe %s (%x vs %x)\n",
input_dev->name, devid, revid);
err = -ENODEV;
goto err_free_mem;
}
ts->cmd_crtl3 = AD7879_YPLUS_BIT |
AD7879_XPLUS_BIT |
AD7879_Z2_BIT |
AD7879_Z1_BIT |
AD7879_TEMPMASK_BIT |
AD7879_AUXVBATMASK_BIT |
AD7879_GPIOALERTMASK_BIT;
ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
AD7879_AVG(ts->averaging) |
AD7879_MFS(ts->median) |
AD7879_FCD(ts->first_conversion_delay);
ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
AD7879_ACQ(ts->acquisition_time) |
AD7879_TMR(ts->pen_down_acc_interval);
err = request_threaded_irq(ts->irq, NULL, ad7879_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
dev_name(dev), ts);
if (err) {
dev_err(dev, "irq %d busy?\n", ts->irq);
goto err_free_mem;
}
__ad7879_disable(ts);
err = sysfs_create_group(&dev->kobj, &ad7879_attr_group);
if (err)
goto err_free_irq;
err = ad7879_gpio_add(ts, pdata);
if (err)
goto err_remove_attr;
err = input_register_device(input_dev);
if (err)
goto err_remove_gpio;
return ts;
err_remove_gpio:
ad7879_gpio_remove(ts);
err_remove_attr:
sysfs_remove_group(&dev->kobj, &ad7879_attr_group);
err_free_irq:
free_irq(ts->irq, ts);
err_free_mem:
input_free_device(input_dev);
kfree(ts);
err_out:
return ERR_PTR(err);
}
EXPORT_SYMBOL(ad7879_probe);
void ad7879_remove(struct ad7879 *ts)
{
ad7879_gpio_remove(ts);
sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
free_irq(ts->irq, ts);
input_unregister_device(ts->input);
kfree(ts);
}
EXPORT_SYMBOL(ad7879_remove);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,30 @@
/*
* AD7879/AD7889 touchscreen (bus interfaces)
*
* Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef _AD7879_H_
#define _AD7879_H_
#include <linux/types.h>
struct ad7879;
struct device;
struct ad7879_bus_ops {
u16 bustype;
int (*read)(struct device *dev, u8 reg);
int (*multi_read)(struct device *dev, u8 first_reg, u8 count, u16 *buf);
int (*write)(struct device *dev, u8 reg, u16 val);
};
extern const struct dev_pm_ops ad7879_pm_ops;
struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq,
const struct ad7879_bus_ops *bops);
void ad7879_remove(struct ad7879 *);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,181 @@
/*
* Microchip AR1021 driver for I2C
*
* Author: Christian Gmeiner <christian.gmeiner@gmail.com>
*
* License: GPLv2 as published by the FSF.
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/of.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#define AR1021_TOCUH_PKG_SIZE 5
#define AR1021_MAX_X 4095
#define AR1021_MAX_Y 4095
struct ar1021_i2c {
struct i2c_client *client;
struct input_dev *input;
u8 data[AR1021_TOCUH_PKG_SIZE];
};
static irqreturn_t ar1021_i2c_irq(int irq, void *dev_id)
{
struct ar1021_i2c *ar1021 = dev_id;
struct input_dev *input = ar1021->input;
u8 *data = ar1021->data;
unsigned int x, y, button;
int retval;
retval = i2c_master_recv(ar1021->client,
ar1021->data, sizeof(ar1021->data));
if (retval != sizeof(ar1021->data))
goto out;
/* sync bit set ? */
if ((data[0] & 0x80) == 0)
goto out;
button = data[0] & BIT(0);
x = ((data[2] & 0x1f) << 7) | (data[1] & 0x7f);
y = ((data[4] & 0x1f) << 7) | (data[3] & 0x7f);
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
input_report_key(input, BTN_TOUCH, button);
input_sync(input);
out:
return IRQ_HANDLED;
}
static int ar1021_i2c_open(struct input_dev *dev)
{
struct ar1021_i2c *ar1021 = input_get_drvdata(dev);
struct i2c_client *client = ar1021->client;
enable_irq(client->irq);
return 0;
}
static void ar1021_i2c_close(struct input_dev *dev)
{
struct ar1021_i2c *ar1021 = input_get_drvdata(dev);
struct i2c_client *client = ar1021->client;
disable_irq(client->irq);
}
static int ar1021_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ar1021_i2c *ar1021;
struct input_dev *input;
int error;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "i2c_check_functionality error\n");
return -ENXIO;
}
ar1021 = devm_kzalloc(&client->dev, sizeof(*ar1021), GFP_KERNEL);
if (!ar1021)
return -ENOMEM;
input = devm_input_allocate_device(&client->dev);
if (!input)
return -ENOMEM;
ar1021->client = client;
ar1021->input = input;
input->name = "ar1021 I2C Touchscreen";
input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev;
input->open = ar1021_i2c_open;
input->close = ar1021_i2c_close;
input_set_capability(input, EV_KEY, BTN_TOUCH);
input_set_abs_params(input, ABS_X, 0, AR1021_MAX_X, 0, 0);
input_set_abs_params(input, ABS_Y, 0, AR1021_MAX_Y, 0, 0);
input_set_drvdata(input, ar1021);
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, ar1021_i2c_irq,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"ar1021_i2c", ar1021);
if (error) {
dev_err(&client->dev,
"Failed to enable IRQ, error: %d\n", error);
return error;
}
/* Disable the IRQ, we'll enable it in ar1021_i2c_open() */
disable_irq(client->irq);
error = input_register_device(ar1021->input);
if (error) {
dev_err(&client->dev,
"Failed to register input device, error: %d\n", error);
return error;
}
i2c_set_clientdata(client, ar1021);
return 0;
}
static int __maybe_unused ar1021_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
disable_irq(client->irq);
return 0;
}
static int __maybe_unused ar1021_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
enable_irq(client->irq);
return 0;
}
static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume);
static const struct i2c_device_id ar1021_i2c_id[] = {
{ "MICROCHIP_AR1021_I2C", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id);
static struct of_device_id ar1021_i2c_of_match[] = {
{ .compatible = "microchip,ar1021-i2c", },
{ }
};
MODULE_DEVICE_TABLE(of, ar1021_i2c_of_match);
static struct i2c_driver ar1021_i2c_driver = {
.driver = {
.name = "ar1021_i2c",
.owner = THIS_MODULE,
.pm = &ar1021_i2c_pm,
.of_match_table = ar1021_i2c_of_match,
},
.probe = ar1021_i2c_probe,
.id_table = ar1021_i2c_id,
};
module_i2c_driver(ar1021_i2c_driver);
MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
MODULE_DESCRIPTION("Microchip AR1021 I2C Driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,437 @@
/*
* Atmel AT91 and AVR32 continuous touch screen driver for Wolfson WM97xx AC97
* codecs.
*
* Copyright (C) 2008 - 2009 Atmel Corporation
*
* 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/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/wm97xx.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/slab.h>
#define AC97C_ICA 0x10
#define AC97C_CBRHR 0x30
#define AC97C_CBSR 0x38
#define AC97C_CBMR 0x3c
#define AC97C_IER 0x54
#define AC97C_IDR 0x58
#define AC97C_RXRDY (1 << 4)
#define AC97C_OVRUN (1 << 5)
#define AC97C_CMR_SIZE_20 (0 << 16)
#define AC97C_CMR_SIZE_18 (1 << 16)
#define AC97C_CMR_SIZE_16 (2 << 16)
#define AC97C_CMR_SIZE_10 (3 << 16)
#define AC97C_CMR_CEM_LITTLE (1 << 18)
#define AC97C_CMR_CEM_BIG (0 << 18)
#define AC97C_CMR_CENA (1 << 21)
#define AC97C_INT_CBEVT (1 << 4)
#define AC97C_SR_CAEVT (1 << 3)
#define AC97C_CH_MASK(slot) \
(0x7 << (3 * (slot - 3)))
#define AC97C_CH_ASSIGN(slot, channel) \
(AC97C_CHANNEL_##channel << (3 * (slot - 3)))
#define AC97C_CHANNEL_NONE 0x0
#define AC97C_CHANNEL_B 0x2
#define ac97c_writel(chip, reg, val) \
__raw_writel((val), (chip)->regs + AC97C_##reg)
#define ac97c_readl(chip, reg) \
__raw_readl((chip)->regs + AC97C_##reg)
#ifdef CONFIG_CPU_AT32AP700X
#define ATMEL_WM97XX_AC97C_IOMEM (0xfff02800)
#define ATMEL_WM97XX_AC97C_IRQ (29)
#define ATMEL_WM97XX_GPIO_DEFAULT (32+16) /* Pin 16 on port B. */
#else
#error Unknown CPU, this driver only supports AT32AP700X CPUs.
#endif
struct continuous {
u16 id; /* codec id */
u8 code; /* continuous code */
u8 reads; /* number of coord reads per read cycle */
u32 speed; /* number of coords per second */
};
#define WM_READS(sp) ((sp / HZ) + 1)
static const struct continuous cinfo[] = {
{WM9705_ID2, 0, WM_READS(94), 94},
{WM9705_ID2, 1, WM_READS(188), 188},
{WM9705_ID2, 2, WM_READS(375), 375},
{WM9705_ID2, 3, WM_READS(750), 750},
{WM9712_ID2, 0, WM_READS(94), 94},
{WM9712_ID2, 1, WM_READS(188), 188},
{WM9712_ID2, 2, WM_READS(375), 375},
{WM9712_ID2, 3, WM_READS(750), 750},
{WM9713_ID2, 0, WM_READS(94), 94},
{WM9713_ID2, 1, WM_READS(120), 120},
{WM9713_ID2, 2, WM_READS(154), 154},
{WM9713_ID2, 3, WM_READS(188), 188},
};
/* Continuous speed index. */
static int sp_idx;
/*
* Pen sampling frequency (Hz) in continuous mode.
*/
static int cont_rate = 188;
module_param(cont_rate, int, 0);
MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
/*
* Pen down detection.
*
* This driver can either poll or use an interrupt to indicate a pen down
* event. If the irq request fails then it will fall back to polling mode.
*/
static int pen_int = 1;
module_param(pen_int, int, 0);
MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
/*
* Pressure readback.
*
* Set to 1 to read back pen down pressure.
*/
static int pressure;
module_param(pressure, int, 0);
MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
/*
* AC97 touch data slot.
*
* Touch screen readback data ac97 slot.
*/
static int ac97_touch_slot = 5;
module_param(ac97_touch_slot, int, 0);
MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
/*
* GPIO line number.
*
* Set to GPIO number where the signal from the WM97xx device is hooked up.
*/
static int atmel_gpio_line = ATMEL_WM97XX_GPIO_DEFAULT;
module_param(atmel_gpio_line, int, 0);
MODULE_PARM_DESC(atmel_gpio_line, "GPIO line number connected to WM97xx");
struct atmel_wm97xx {
struct wm97xx *wm;
struct timer_list pen_timer;
void __iomem *regs;
unsigned long ac97c_irq;
unsigned long gpio_pen;
unsigned long gpio_irq;
unsigned short x;
unsigned short y;
};
static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id)
{
struct atmel_wm97xx *atmel_wm97xx = dev_id;
struct wm97xx *wm = atmel_wm97xx->wm;
int status = ac97c_readl(atmel_wm97xx, CBSR);
irqreturn_t retval = IRQ_NONE;
if (status & AC97C_OVRUN) {
dev_dbg(&wm->touch_dev->dev, "AC97C overrun\n");
ac97c_readl(atmel_wm97xx, CBRHR);
retval = IRQ_HANDLED;
} else if (status & AC97C_RXRDY) {
u16 data;
u16 value;
u16 source;
u16 pen_down;
data = ac97c_readl(atmel_wm97xx, CBRHR);
value = data & 0x0fff;
source = data & WM97XX_ADCSEL_MASK;
pen_down = (data & WM97XX_PEN_DOWN) >> 8;
if (source == WM97XX_ADCSEL_X)
atmel_wm97xx->x = value;
if (source == WM97XX_ADCSEL_Y)
atmel_wm97xx->y = value;
if (!pressure && source == WM97XX_ADCSEL_Y) {
input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
input_report_key(wm->input_dev, BTN_TOUCH, pen_down);
input_sync(wm->input_dev);
} else if (pressure && source == WM97XX_ADCSEL_PRES) {
input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
input_report_abs(wm->input_dev, ABS_PRESSURE, value);
input_report_key(wm->input_dev, BTN_TOUCH, value);
input_sync(wm->input_dev);
}
retval = IRQ_HANDLED;
}
return retval;
}
static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm)
{
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
struct input_dev *input_dev = wm->input_dev;
int pen_down = gpio_get_value(atmel_wm97xx->gpio_pen);
if (pen_down != 0) {
mod_timer(&atmel_wm97xx->pen_timer,
jiffies + msecs_to_jiffies(1));
} else {
if (pressure)
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
}
}
static void atmel_wm97xx_pen_timer(unsigned long data)
{
atmel_wm97xx_acc_pen_up((struct wm97xx *)data);
}
static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
{
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
int idx = 0;
if (wm->ac97 == NULL)
return -ENODEV;
for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
if (wm->id != cinfo[idx].id)
continue;
sp_idx = idx;
if (cont_rate <= cinfo[idx].speed)
break;
}
wm->acc_rate = cinfo[sp_idx].code;
wm->acc_slot = ac97_touch_slot;
dev_info(&wm->touch_dev->dev, "atmel accelerated touchscreen driver, "
"%d samples/sec\n", cinfo[sp_idx].speed);
if (pen_int) {
unsigned long reg;
wm->pen_irq = atmel_wm97xx->gpio_irq;
switch (wm->id) {
case WM9712_ID2: /* Fall through. */
case WM9713_ID2:
/*
* Use GPIO 13 (PEN_DOWN) to assert GPIO line 3
* (PENDOWN).
*/
wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
WM97XX_GPIO_POL_HIGH,
WM97XX_GPIO_STICKY,
WM97XX_GPIO_WAKE);
wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT,
WM97XX_GPIO_POL_HIGH,
WM97XX_GPIO_NOTSTICKY,
WM97XX_GPIO_NOWAKE);
case WM9705_ID2: /* Fall through. */
/*
* Enable touch data slot in AC97 controller channel B.
*/
reg = ac97c_readl(atmel_wm97xx, ICA);
reg &= ~AC97C_CH_MASK(wm->acc_slot);
reg |= AC97C_CH_ASSIGN(wm->acc_slot, B);
ac97c_writel(atmel_wm97xx, ICA, reg);
/*
* Enable channel and interrupt for RXRDY and OVERRUN.
*/
ac97c_writel(atmel_wm97xx, CBMR, AC97C_CMR_CENA
| AC97C_CMR_CEM_BIG
| AC97C_CMR_SIZE_16
| AC97C_OVRUN
| AC97C_RXRDY);
/* Dummy read to empty RXRHR. */
ac97c_readl(atmel_wm97xx, CBRHR);
/*
* Enable interrupt for channel B in the AC97
* controller.
*/
ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
break;
default:
dev_err(&wm->touch_dev->dev, "pen down irq not "
"supported on this device\n");
pen_int = 0;
break;
}
}
return 0;
}
static void atmel_wm97xx_acc_shutdown(struct wm97xx *wm)
{
if (pen_int) {
struct atmel_wm97xx *atmel_wm97xx =
platform_get_drvdata(wm->touch_dev);
unsigned long ica;
switch (wm->id & 0xffff) {
case WM9705_ID2: /* Fall through. */
case WM9712_ID2: /* Fall through. */
case WM9713_ID2:
/* Disable slot and turn off channel B interrupts. */
ica = ac97c_readl(atmel_wm97xx, ICA);
ica &= ~AC97C_CH_MASK(wm->acc_slot);
ac97c_writel(atmel_wm97xx, ICA, ica);
ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
ac97c_writel(atmel_wm97xx, CBMR, 0);
wm->pen_irq = 0;
break;
default:
dev_err(&wm->touch_dev->dev, "unknown codec\n");
break;
}
}
}
static void atmel_wm97xx_irq_enable(struct wm97xx *wm, int enable)
{
/* Intentionally left empty. */
}
static struct wm97xx_mach_ops atmel_mach_ops = {
.acc_enabled = 1,
.acc_pen_up = atmel_wm97xx_acc_pen_up,
.acc_startup = atmel_wm97xx_acc_startup,
.acc_shutdown = atmel_wm97xx_acc_shutdown,
.irq_enable = atmel_wm97xx_irq_enable,
.irq_gpio = WM97XX_GPIO_3,
};
static int __init atmel_wm97xx_probe(struct platform_device *pdev)
{
struct wm97xx *wm = platform_get_drvdata(pdev);
struct atmel_wm97xx *atmel_wm97xx;
int ret;
atmel_wm97xx = kzalloc(sizeof(struct atmel_wm97xx), GFP_KERNEL);
if (!atmel_wm97xx) {
dev_dbg(&pdev->dev, "out of memory\n");
return -ENOMEM;
}
atmel_wm97xx->wm = wm;
atmel_wm97xx->regs = (void *)ATMEL_WM97XX_AC97C_IOMEM;
atmel_wm97xx->ac97c_irq = ATMEL_WM97XX_AC97C_IRQ;
atmel_wm97xx->gpio_pen = atmel_gpio_line;
atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen);
setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer,
(unsigned long)wm);
ret = request_irq(atmel_wm97xx->ac97c_irq,
atmel_wm97xx_channel_b_interrupt,
IRQF_SHARED, "atmel-wm97xx-ch-b", atmel_wm97xx);
if (ret) {
dev_dbg(&pdev->dev, "could not request ac97c irq\n");
goto err;
}
platform_set_drvdata(pdev, atmel_wm97xx);
ret = wm97xx_register_mach_ops(wm, &atmel_mach_ops);
if (ret)
goto err_irq;
return ret;
err_irq:
free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
err:
kfree(atmel_wm97xx);
return ret;
}
static int __exit atmel_wm97xx_remove(struct platform_device *pdev)
{
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
struct wm97xx *wm = atmel_wm97xx->wm;
ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
del_timer_sync(&atmel_wm97xx->pen_timer);
wm97xx_unregister_mach_ops(wm);
kfree(atmel_wm97xx);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int atmel_wm97xx_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
disable_irq(atmel_wm97xx->gpio_irq);
del_timer_sync(&atmel_wm97xx->pen_timer);
return 0;
}
static int atmel_wm97xx_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
struct wm97xx *wm = atmel_wm97xx->wm;
if (wm->input_dev->users) {
enable_irq(atmel_wm97xx->gpio_irq);
ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(atmel_wm97xx_pm_ops,
atmel_wm97xx_suspend, atmel_wm97xx_resume);
static struct platform_driver atmel_wm97xx_driver = {
.remove = __exit_p(atmel_wm97xx_remove),
.driver = {
.name = "wm97xx-touch",
.owner = THIS_MODULE,
.pm = &atmel_wm97xx_pm_ops,
},
};
module_platform_driver_probe(atmel_wm97xx_driver, atmel_wm97xx_probe);
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,704 @@
/*
* Driver for AUO in-cell touchscreens
*
* Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de>
*
* loosely based on auo_touch.c from Dell Streak vendor-kernel
*
* Copyright (c) 2008 QUALCOMM Incorporated.
* Copyright (c) 2008 QUALCOMM USA, INC.
*
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/input/auo-pixcir-ts.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
/*
* Coordinate calculation:
* X1 = X1_LSB + X1_MSB*256
* Y1 = Y1_LSB + Y1_MSB*256
* X2 = X2_LSB + X2_MSB*256
* Y2 = Y2_LSB + Y2_MSB*256
*/
#define AUO_PIXCIR_REG_X1_LSB 0x00
#define AUO_PIXCIR_REG_X1_MSB 0x01
#define AUO_PIXCIR_REG_Y1_LSB 0x02
#define AUO_PIXCIR_REG_Y1_MSB 0x03
#define AUO_PIXCIR_REG_X2_LSB 0x04
#define AUO_PIXCIR_REG_X2_MSB 0x05
#define AUO_PIXCIR_REG_Y2_LSB 0x06
#define AUO_PIXCIR_REG_Y2_MSB 0x07
#define AUO_PIXCIR_REG_STRENGTH 0x0d
#define AUO_PIXCIR_REG_STRENGTH_X1_LSB 0x0e
#define AUO_PIXCIR_REG_STRENGTH_X1_MSB 0x0f
#define AUO_PIXCIR_REG_RAW_DATA_X 0x2b
#define AUO_PIXCIR_REG_RAW_DATA_Y 0x4f
#define AUO_PIXCIR_REG_X_SENSITIVITY 0x6f
#define AUO_PIXCIR_REG_Y_SENSITIVITY 0x70
#define AUO_PIXCIR_REG_INT_SETTING 0x71
#define AUO_PIXCIR_REG_INT_WIDTH 0x72
#define AUO_PIXCIR_REG_POWER_MODE 0x73
#define AUO_PIXCIR_REG_VERSION 0x77
#define AUO_PIXCIR_REG_CALIBRATE 0x78
#define AUO_PIXCIR_REG_TOUCHAREA_X1 0x1e
#define AUO_PIXCIR_REG_TOUCHAREA_Y1 0x1f
#define AUO_PIXCIR_REG_TOUCHAREA_X2 0x20
#define AUO_PIXCIR_REG_TOUCHAREA_Y2 0x21
#define AUO_PIXCIR_REG_EEPROM_CALIB_X 0x42
#define AUO_PIXCIR_REG_EEPROM_CALIB_Y 0xad
#define AUO_PIXCIR_INT_TPNUM_MASK 0xe0
#define AUO_PIXCIR_INT_TPNUM_SHIFT 5
#define AUO_PIXCIR_INT_RELEASE (1 << 4)
#define AUO_PIXCIR_INT_ENABLE (1 << 3)
#define AUO_PIXCIR_INT_POL_HIGH (1 << 2)
#define AUO_PIXCIR_INT_MODE_MASK 0x03
/*
* Power modes:
* active: scan speed 60Hz
* sleep: scan speed 10Hz can be auto-activated, wakeup on 1st touch
* deep sleep: scan speed 1Hz can only be entered or left manually.
*/
#define AUO_PIXCIR_POWER_ACTIVE 0x00
#define AUO_PIXCIR_POWER_SLEEP 0x01
#define AUO_PIXCIR_POWER_DEEP_SLEEP 0x02
#define AUO_PIXCIR_POWER_MASK 0x03
#define AUO_PIXCIR_POWER_ALLOW_SLEEP (1 << 2)
#define AUO_PIXCIR_POWER_IDLE_TIME(ms) ((ms & 0xf) << 4)
#define AUO_PIXCIR_CALIBRATE 0x03
#define AUO_PIXCIR_EEPROM_CALIB_X_LEN 62
#define AUO_PIXCIR_EEPROM_CALIB_Y_LEN 36
#define AUO_PIXCIR_RAW_DATA_X_LEN 18
#define AUO_PIXCIR_RAW_DATA_Y_LEN 11
#define AUO_PIXCIR_STRENGTH_ENABLE (1 << 0)
/* Touchscreen absolute values */
#define AUO_PIXCIR_REPORT_POINTS 2
#define AUO_PIXCIR_MAX_AREA 0xff
#define AUO_PIXCIR_PENUP_TIMEOUT_MS 10
struct auo_pixcir_ts {
struct i2c_client *client;
struct input_dev *input;
const struct auo_pixcir_ts_platdata *pdata;
char phys[32];
/* special handling for touch_indicate interupt mode */
bool touch_ind_mode;
wait_queue_head_t wait;
bool stopped;
};
struct auo_point_t {
int coord_x;
int coord_y;
int area_major;
int area_minor;
int orientation;
};
static int auo_pixcir_collect_data(struct auo_pixcir_ts *ts,
struct auo_point_t *point)
{
struct i2c_client *client = ts->client;
const struct auo_pixcir_ts_platdata *pdata = ts->pdata;
uint8_t raw_coord[8];
uint8_t raw_area[4];
int i, ret;
/* touch coordinates */
ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_X1_LSB,
8, raw_coord);
if (ret < 0) {
dev_err(&client->dev, "failed to read coordinate, %d\n", ret);
return ret;
}
/* touch area */
ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_TOUCHAREA_X1,
4, raw_area);
if (ret < 0) {
dev_err(&client->dev, "could not read touch area, %d\n", ret);
return ret;
}
for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
point[i].coord_x =
raw_coord[4 * i + 1] << 8 | raw_coord[4 * i];
point[i].coord_y =
raw_coord[4 * i + 3] << 8 | raw_coord[4 * i + 2];
if (point[i].coord_x > pdata->x_max ||
point[i].coord_y > pdata->y_max) {
dev_warn(&client->dev, "coordinates (%d,%d) invalid\n",
point[i].coord_x, point[i].coord_y);
point[i].coord_x = point[i].coord_y = 0;
}
/* determine touch major, minor and orientation */
point[i].area_major = max(raw_area[2 * i], raw_area[2 * i + 1]);
point[i].area_minor = min(raw_area[2 * i], raw_area[2 * i + 1]);
point[i].orientation = raw_area[2 * i] > raw_area[2 * i + 1];
}
return 0;
}
static irqreturn_t auo_pixcir_interrupt(int irq, void *dev_id)
{
struct auo_pixcir_ts *ts = dev_id;
const struct auo_pixcir_ts_platdata *pdata = ts->pdata;
struct auo_point_t point[AUO_PIXCIR_REPORT_POINTS];
int i;
int ret;
int fingers = 0;
int abs = -1;
while (!ts->stopped) {
/* check for up event in touch touch_ind_mode */
if (ts->touch_ind_mode) {
if (gpio_get_value(pdata->gpio_int) == 0) {
input_mt_sync(ts->input);
input_report_key(ts->input, BTN_TOUCH, 0);
input_sync(ts->input);
break;
}
}
ret = auo_pixcir_collect_data(ts, point);
if (ret < 0) {
/* we want to loop only in touch_ind_mode */
if (!ts->touch_ind_mode)
break;
wait_event_timeout(ts->wait, ts->stopped,
msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS));
continue;
}
for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
if (point[i].coord_x > 0 || point[i].coord_y > 0) {
input_report_abs(ts->input, ABS_MT_POSITION_X,
point[i].coord_x);
input_report_abs(ts->input, ABS_MT_POSITION_Y,
point[i].coord_y);
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
point[i].area_major);
input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
point[i].area_minor);
input_report_abs(ts->input, ABS_MT_ORIENTATION,
point[i].orientation);
input_mt_sync(ts->input);
/* use first finger as source for singletouch */
if (fingers == 0)
abs = i;
/* number of touch points could also be queried
* via i2c but would require an additional call
*/
fingers++;
}
}
input_report_key(ts->input, BTN_TOUCH, fingers > 0);
if (abs > -1) {
input_report_abs(ts->input, ABS_X, point[abs].coord_x);
input_report_abs(ts->input, ABS_Y, point[abs].coord_y);
}
input_sync(ts->input);
/* we want to loop only in touch_ind_mode */
if (!ts->touch_ind_mode)
break;
wait_event_timeout(ts->wait, ts->stopped,
msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS));
}
return IRQ_HANDLED;
}
/*
* Set the power mode of the device.
* Valid modes are
* - AUO_PIXCIR_POWER_ACTIVE
* - AUO_PIXCIR_POWER_SLEEP - automatically left on first touch
* - AUO_PIXCIR_POWER_DEEP_SLEEP
*/
static int auo_pixcir_power_mode(struct auo_pixcir_ts *ts, int mode)
{
struct i2c_client *client = ts->client;
int ret;
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_POWER_MODE);
if (ret < 0) {
dev_err(&client->dev, "unable to read reg %Xh, %d\n",
AUO_PIXCIR_REG_POWER_MODE, ret);
return ret;
}
ret &= ~AUO_PIXCIR_POWER_MASK;
ret |= mode;
ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_POWER_MODE, ret);
if (ret) {
dev_err(&client->dev, "unable to write reg %Xh, %d\n",
AUO_PIXCIR_REG_POWER_MODE, ret);
return ret;
}
return 0;
}
static int auo_pixcir_int_config(struct auo_pixcir_ts *ts,
int int_setting)
{
struct i2c_client *client = ts->client;
const struct auo_pixcir_ts_platdata *pdata = ts->pdata;
int ret;
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
if (ret < 0) {
dev_err(&client->dev, "unable to read reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
ret &= ~AUO_PIXCIR_INT_MODE_MASK;
ret |= int_setting;
ret |= AUO_PIXCIR_INT_POL_HIGH; /* always use high for interrupts */
ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING,
ret);
if (ret < 0) {
dev_err(&client->dev, "unable to write reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
ts->touch_ind_mode = pdata->int_setting == AUO_PIXCIR_INT_TOUCH_IND;
return 0;
}
/* control the generation of interrupts on the device side */
static int auo_pixcir_int_toggle(struct auo_pixcir_ts *ts, bool enable)
{
struct i2c_client *client = ts->client;
int ret;
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
if (ret < 0) {
dev_err(&client->dev, "unable to read reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
if (enable)
ret |= AUO_PIXCIR_INT_ENABLE;
else
ret &= ~AUO_PIXCIR_INT_ENABLE;
ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING,
ret);
if (ret < 0) {
dev_err(&client->dev, "unable to write reg %Xh, %d\n",
AUO_PIXCIR_REG_INT_SETTING, ret);
return ret;
}
return 0;
}
static int auo_pixcir_start(struct auo_pixcir_ts *ts)
{
struct i2c_client *client = ts->client;
int ret;
ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_ACTIVE);
if (ret < 0) {
dev_err(&client->dev, "could not set power mode, %d\n",
ret);
return ret;
}
ts->stopped = false;
mb();
enable_irq(client->irq);
ret = auo_pixcir_int_toggle(ts, 1);
if (ret < 0) {
dev_err(&client->dev, "could not enable interrupt, %d\n",
ret);
disable_irq(client->irq);
return ret;
}
return 0;
}
static int auo_pixcir_stop(struct auo_pixcir_ts *ts)
{
struct i2c_client *client = ts->client;
int ret;
ret = auo_pixcir_int_toggle(ts, 0);
if (ret < 0) {
dev_err(&client->dev, "could not disable interrupt, %d\n",
ret);
return ret;
}
/* disable receiving of interrupts */
disable_irq(client->irq);
ts->stopped = true;
mb();
wake_up(&ts->wait);
return auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_DEEP_SLEEP);
}
static int auo_pixcir_input_open(struct input_dev *dev)
{
struct auo_pixcir_ts *ts = input_get_drvdata(dev);
int ret;
ret = auo_pixcir_start(ts);
if (ret)
return ret;
return 0;
}
static void auo_pixcir_input_close(struct input_dev *dev)
{
struct auo_pixcir_ts *ts = input_get_drvdata(dev);
auo_pixcir_stop(ts);
return;
}
#ifdef CONFIG_PM_SLEEP
static int auo_pixcir_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
mutex_lock(&input->mutex);
/* when configured as wakeup source, device should always wake system
* therefore start device if necessary
*/
if (device_may_wakeup(&client->dev)) {
/* need to start device if not open, to be wakeup source */
if (!input->users) {
ret = auo_pixcir_start(ts);
if (ret)
goto unlock;
}
enable_irq_wake(client->irq);
ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP);
} else if (input->users) {
ret = auo_pixcir_stop(ts);
}
unlock:
mutex_unlock(&input->mutex);
return ret;
}
static int auo_pixcir_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
mutex_lock(&input->mutex);
if (device_may_wakeup(&client->dev)) {
disable_irq_wake(client->irq);
/* need to stop device if it was not open on suspend */
if (!input->users) {
ret = auo_pixcir_stop(ts);
if (ret)
goto unlock;
}
/* device wakes automatically from SLEEP */
} else if (input->users) {
ret = auo_pixcir_start(ts);
}
unlock:
mutex_unlock(&input->mutex);
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops,
auo_pixcir_suspend, auo_pixcir_resume);
#ifdef CONFIG_OF
static struct auo_pixcir_ts_platdata *auo_pixcir_parse_dt(struct device *dev)
{
struct auo_pixcir_ts_platdata *pdata;
struct device_node *np = dev->of_node;
if (!np)
return ERR_PTR(-ENOENT);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "failed to allocate platform data\n");
return ERR_PTR(-ENOMEM);
}
pdata->gpio_int = of_get_gpio(np, 0);
if (!gpio_is_valid(pdata->gpio_int)) {
dev_err(dev, "failed to get interrupt gpio\n");
return ERR_PTR(-EINVAL);
}
pdata->gpio_rst = of_get_gpio(np, 1);
if (!gpio_is_valid(pdata->gpio_rst)) {
dev_err(dev, "failed to get reset gpio\n");
return ERR_PTR(-EINVAL);
}
if (of_property_read_u32(np, "x-size", &pdata->x_max)) {
dev_err(dev, "failed to get x-size property\n");
return ERR_PTR(-EINVAL);
}
if (of_property_read_u32(np, "y-size", &pdata->y_max)) {
dev_err(dev, "failed to get y-size property\n");
return ERR_PTR(-EINVAL);
}
/* default to asserting the interrupt when the screen is touched */
pdata->int_setting = AUO_PIXCIR_INT_TOUCH_IND;
return pdata;
}
#else
static struct auo_pixcir_ts_platdata *auo_pixcir_parse_dt(struct device *dev)
{
return ERR_PTR(-EINVAL);
}
#endif
static void auo_pixcir_reset(void *data)
{
struct auo_pixcir_ts *ts = data;
gpio_set_value(ts->pdata->gpio_rst, 0);
}
static int auo_pixcir_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct auo_pixcir_ts_platdata *pdata;
struct auo_pixcir_ts *ts;
struct input_dev *input_dev;
int version;
int error;
pdata = dev_get_platdata(&client->dev);
if (!pdata) {
pdata = auo_pixcir_parse_dt(&client->dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
ts = devm_kzalloc(&client->dev,
sizeof(struct auo_pixcir_ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev) {
dev_err(&client->dev, "could not allocate input device\n");
return -ENOMEM;
}
ts->pdata = pdata;
ts->client = client;
ts->input = input_dev;
ts->touch_ind_mode = 0;
ts->stopped = true;
init_waitqueue_head(&ts->wait);
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
input_dev->name = "AUO-Pixcir touchscreen";
input_dev->phys = ts->phys;
input_dev->id.bustype = BUS_I2C;
input_dev->open = auo_pixcir_input_open;
input_dev->close = auo_pixcir_input_close;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
/* For single touch */
input_set_abs_params(input_dev, ABS_X, 0, pdata->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, pdata->y_max, 0, 0);
/* For multi touch */
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
pdata->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
pdata->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
AUO_PIXCIR_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0,
AUO_PIXCIR_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
input_set_drvdata(ts->input, ts);
error = devm_gpio_request_one(&client->dev, pdata->gpio_int,
GPIOF_DIR_IN, "auo_pixcir_ts_int");
if (error) {
dev_err(&client->dev, "request of gpio %d failed, %d\n",
pdata->gpio_int, error);
return error;
}
error = devm_gpio_request_one(&client->dev, pdata->gpio_rst,
GPIOF_DIR_OUT | GPIOF_INIT_HIGH,
"auo_pixcir_ts_rst");
if (error) {
dev_err(&client->dev, "request of gpio %d failed, %d\n",
pdata->gpio_rst, error);
return error;
}
error = devm_add_action(&client->dev, auo_pixcir_reset, ts);
if (error) {
auo_pixcir_reset(ts);
dev_err(&client->dev, "failed to register reset action, %d\n",
error);
return error;
}
msleep(200);
version = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_VERSION);
if (version < 0) {
error = version;
return error;
}
dev_info(&client->dev, "firmware version 0x%X\n", version);
error = auo_pixcir_int_config(ts, pdata->int_setting);
if (error)
return error;
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, auo_pixcir_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
input_dev->name, ts);
if (error) {
dev_err(&client->dev, "irq %d requested failed, %d\n",
client->irq, error);
return error;
}
/* stop device and put it into deep sleep until it is opened */
error = auo_pixcir_stop(ts);
if (error)
return error;
error = input_register_device(input_dev);
if (error) {
dev_err(&client->dev, "could not register input device, %d\n",
error);
return error;
}
i2c_set_clientdata(client, ts);
return 0;
}
static const struct i2c_device_id auo_pixcir_idtable[] = {
{ "auo_pixcir_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
#ifdef CONFIG_OF
static const struct of_device_id auo_pixcir_ts_dt_idtable[] = {
{ .compatible = "auo,auo_pixcir_ts" },
{},
};
MODULE_DEVICE_TABLE(of, auo_pixcir_ts_dt_idtable);
#endif
static struct i2c_driver auo_pixcir_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "auo_pixcir_ts",
.pm = &auo_pixcir_pm_ops,
.of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable),
},
.probe = auo_pixcir_probe,
.id_table = auo_pixcir_idtable,
};
module_i2c_driver(auo_pixcir_driver);
MODULE_DESCRIPTION("AUO-PIXCIR touchscreen driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");

View file

@ -0,0 +1,733 @@
/*
* Copyright (C) ST-Ericsson SA 2010
* Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
* License terms:GNU General Public License (GPL) version 2
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <linux/input.h>
#include <linux/input/bu21013.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#define PEN_DOWN_INTR 0
#define MAX_FINGERS 2
#define RESET_DELAY 30
#define PENUP_TIMEOUT (10)
#define DELTA_MIN 16
#define MASK_BITS 0x03
#define SHIFT_8 8
#define SHIFT_2 2
#define LENGTH_OF_BUFFER 11
#define I2C_RETRY_COUNT 5
#define BU21013_SENSORS_BTN_0_7_REG 0x70
#define BU21013_SENSORS_BTN_8_15_REG 0x71
#define BU21013_SENSORS_BTN_16_23_REG 0x72
#define BU21013_X1_POS_MSB_REG 0x73
#define BU21013_X1_POS_LSB_REG 0x74
#define BU21013_Y1_POS_MSB_REG 0x75
#define BU21013_Y1_POS_LSB_REG 0x76
#define BU21013_X2_POS_MSB_REG 0x77
#define BU21013_X2_POS_LSB_REG 0x78
#define BU21013_Y2_POS_MSB_REG 0x79
#define BU21013_Y2_POS_LSB_REG 0x7A
#define BU21013_INT_CLR_REG 0xE8
#define BU21013_INT_MODE_REG 0xE9
#define BU21013_GAIN_REG 0xEA
#define BU21013_OFFSET_MODE_REG 0xEB
#define BU21013_XY_EDGE_REG 0xEC
#define BU21013_RESET_REG 0xED
#define BU21013_CALIB_REG 0xEE
#define BU21013_DONE_REG 0xEF
#define BU21013_SENSOR_0_7_REG 0xF0
#define BU21013_SENSOR_8_15_REG 0xF1
#define BU21013_SENSOR_16_23_REG 0xF2
#define BU21013_POS_MODE1_REG 0xF3
#define BU21013_POS_MODE2_REG 0xF4
#define BU21013_CLK_MODE_REG 0xF5
#define BU21013_IDLE_REG 0xFA
#define BU21013_FILTER_REG 0xFB
#define BU21013_TH_ON_REG 0xFC
#define BU21013_TH_OFF_REG 0xFD
#define BU21013_RESET_ENABLE 0x01
#define BU21013_SENSORS_EN_0_7 0x3F
#define BU21013_SENSORS_EN_8_15 0xFC
#define BU21013_SENSORS_EN_16_23 0x1F
#define BU21013_POS_MODE1_0 0x02
#define BU21013_POS_MODE1_1 0x04
#define BU21013_POS_MODE1_2 0x08
#define BU21013_POS_MODE2_ZERO 0x01
#define BU21013_POS_MODE2_AVG1 0x02
#define BU21013_POS_MODE2_AVG2 0x04
#define BU21013_POS_MODE2_EN_XY 0x08
#define BU21013_POS_MODE2_EN_RAW 0x10
#define BU21013_POS_MODE2_MULTI 0x80
#define BU21013_CLK_MODE_DIV 0x01
#define BU21013_CLK_MODE_EXT 0x02
#define BU21013_CLK_MODE_CALIB 0x80
#define BU21013_IDLET_0 0x01
#define BU21013_IDLET_1 0x02
#define BU21013_IDLET_2 0x04
#define BU21013_IDLET_3 0x08
#define BU21013_IDLE_INTERMIT_EN 0x10
#define BU21013_DELTA_0_6 0x7F
#define BU21013_FILTER_EN 0x80
#define BU21013_INT_MODE_LEVEL 0x00
#define BU21013_INT_MODE_EDGE 0x01
#define BU21013_GAIN_0 0x01
#define BU21013_GAIN_1 0x02
#define BU21013_GAIN_2 0x04
#define BU21013_OFFSET_MODE_DEFAULT 0x00
#define BU21013_OFFSET_MODE_MOVE 0x01
#define BU21013_OFFSET_MODE_DISABLE 0x02
#define BU21013_TH_ON_0 0x01
#define BU21013_TH_ON_1 0x02
#define BU21013_TH_ON_2 0x04
#define BU21013_TH_ON_3 0x08
#define BU21013_TH_ON_4 0x10
#define BU21013_TH_ON_5 0x20
#define BU21013_TH_ON_6 0x40
#define BU21013_TH_ON_7 0x80
#define BU21013_TH_ON_MAX 0xFF
#define BU21013_TH_OFF_0 0x01
#define BU21013_TH_OFF_1 0x02
#define BU21013_TH_OFF_2 0x04
#define BU21013_TH_OFF_3 0x08
#define BU21013_TH_OFF_4 0x10
#define BU21013_TH_OFF_5 0x20
#define BU21013_TH_OFF_6 0x40
#define BU21013_TH_OFF_7 0x80
#define BU21013_TH_OFF_MAX 0xFF
#define BU21013_X_EDGE_0 0x01
#define BU21013_X_EDGE_1 0x02
#define BU21013_X_EDGE_2 0x04
#define BU21013_X_EDGE_3 0x08
#define BU21013_Y_EDGE_0 0x10
#define BU21013_Y_EDGE_1 0x20
#define BU21013_Y_EDGE_2 0x40
#define BU21013_Y_EDGE_3 0x80
#define BU21013_DONE 0x01
#define BU21013_NUMBER_OF_X_SENSORS (6)
#define BU21013_NUMBER_OF_Y_SENSORS (11)
#define DRIVER_TP "bu21013_tp"
/**
* struct bu21013_ts_data - touch panel data structure
* @client: pointer to the i2c client
* @wait: variable to wait_queue_head_t structure
* @touch_stopped: touch stop flag
* @chip: pointer to the touch panel controller
* @in_dev: pointer to the input device structure
* @intr_pin: interrupt pin value
* @regulator: pointer to the Regulator used for touch screen
*
* Touch panel device data structure
*/
struct bu21013_ts_data {
struct i2c_client *client;
wait_queue_head_t wait;
const struct bu21013_platform_device *chip;
struct input_dev *in_dev;
struct regulator *regulator;
unsigned int irq;
unsigned int intr_pin;
bool touch_stopped;
};
/**
* bu21013_read_block_data(): read the touch co-ordinates
* @data: bu21013_ts_data structure pointer
* @buf: byte pointer
*
* Read the touch co-ordinates using i2c read block into buffer
* and returns integer.
*/
static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf)
{
int ret, i;
for (i = 0; i < I2C_RETRY_COUNT; i++) {
ret = i2c_smbus_read_i2c_block_data
(data->client, BU21013_SENSORS_BTN_0_7_REG,
LENGTH_OF_BUFFER, buf);
if (ret == LENGTH_OF_BUFFER)
return 0;
}
return -EINVAL;
}
/**
* bu21013_do_touch_report(): Get the touch co-ordinates
* @data: bu21013_ts_data structure pointer
*
* Get the touch co-ordinates from touch sensor registers and writes
* into device structure and returns integer.
*/
static int bu21013_do_touch_report(struct bu21013_ts_data *data)
{
u8 buf[LENGTH_OF_BUFFER];
unsigned int pos_x[2], pos_y[2];
bool has_x_sensors, has_y_sensors;
int finger_down_count = 0;
int i;
if (data == NULL)
return -EINVAL;
if (bu21013_read_block_data(data, buf) < 0)
return -EINVAL;
has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7);
has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) |
((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2);
if (!has_x_sensors || !has_y_sensors)
return 0;
for (i = 0; i < MAX_FINGERS; i++) {
const u8 *p = &buf[4 * i + 3];
unsigned int x = p[0] << SHIFT_2 | (p[1] & MASK_BITS);
unsigned int y = p[2] << SHIFT_2 | (p[3] & MASK_BITS);
if (x == 0 || y == 0)
continue;
pos_x[finger_down_count] = x;
pos_y[finger_down_count] = y;
finger_down_count++;
}
if (finger_down_count) {
if (finger_down_count == 2 &&
(abs(pos_x[0] - pos_x[1]) < DELTA_MIN ||
abs(pos_y[0] - pos_y[1]) < DELTA_MIN)) {
return 0;
}
for (i = 0; i < finger_down_count; i++) {
if (data->chip->x_flip)
pos_x[i] = data->chip->touch_x_max - pos_x[i];
if (data->chip->y_flip)
pos_y[i] = data->chip->touch_y_max - pos_y[i];
input_report_abs(data->in_dev,
ABS_MT_POSITION_X, pos_x[i]);
input_report_abs(data->in_dev,
ABS_MT_POSITION_Y, pos_y[i]);
input_mt_sync(data->in_dev);
}
} else
input_mt_sync(data->in_dev);
input_sync(data->in_dev);
return 0;
}
/**
* bu21013_gpio_irq() - gpio thread function for touch interrupt
* @irq: irq value
* @device_data: void pointer
*
* This gpio thread function for touch interrupt
* and returns irqreturn_t.
*/
static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
{
struct bu21013_ts_data *data = device_data;
struct i2c_client *i2c = data->client;
int retval;
do {
retval = bu21013_do_touch_report(data);
if (retval < 0) {
dev_err(&i2c->dev, "bu21013_do_touch_report failed\n");
return IRQ_NONE;
}
data->intr_pin = gpio_get_value(data->chip->touch_pin);
if (data->intr_pin == PEN_DOWN_INTR)
wait_event_timeout(data->wait, data->touch_stopped,
msecs_to_jiffies(2));
} while (!data->intr_pin && !data->touch_stopped);
return IRQ_HANDLED;
}
/**
* bu21013_init_chip() - power on sequence for the bu21013 controller
* @data: device structure pointer
*
* This function is used to power on
* the bu21013 controller and returns integer.
*/
static int bu21013_init_chip(struct bu21013_ts_data *data)
{
int retval;
struct i2c_client *i2c = data->client;
retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET_REG,
BU21013_RESET_ENABLE);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_RESET reg write failed\n");
return retval;
}
msleep(RESET_DELAY);
retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG,
BU21013_SENSORS_EN_0_7);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG,
BU21013_SENSORS_EN_8_15);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG,
BU21013_SENSORS_EN_16_23);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG,
(BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG,
(BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 |
BU21013_POS_MODE2_AVG2 | BU21013_POS_MODE2_EN_RAW |
BU21013_POS_MODE2_MULTI));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_POS_MODE2 reg write failed\n");
return retval;
}
if (data->chip->ext_clk)
retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
(BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB));
else
retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
(BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG,
(BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG,
BU21013_INT_MODE_LEVEL);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG,
(BU21013_DELTA_0_6 |
BU21013_FILTER_EN));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG,
BU21013_TH_ON_5);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
BU21013_TH_OFF_4 | BU21013_TH_OFF_3);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG,
(BU21013_GAIN_0 | BU21013_GAIN_1));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG,
BU21013_OFFSET_MODE_DEFAULT);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG,
(BU21013_X_EDGE_0 | BU21013_X_EDGE_2 |
BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n");
return retval;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG,
BU21013_DONE);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n");
return retval;
}
return 0;
}
/**
* bu21013_free_irq() - frees IRQ registered for touchscreen
* @bu21013_data: device structure pointer
*
* This function signals interrupt thread to stop processing and
* frees interrupt.
*/
static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data)
{
bu21013_data->touch_stopped = true;
wake_up(&bu21013_data->wait);
free_irq(bu21013_data->irq, bu21013_data);
}
/**
* bu21013_cs_disable() - deconfigures the touch panel controller
* @bu21013_data: device structure pointer
*
* This function is used to deconfigure the chip selection
* for touch panel controller.
*/
static void bu21013_cs_disable(struct bu21013_ts_data *bu21013_data)
{
int error;
error = gpio_direction_output(bu21013_data->chip->cs_pin, 0);
if (error < 0)
dev_warn(&bu21013_data->client->dev,
"%s: gpio direction failed, error: %d\n",
__func__, error);
else
gpio_set_value(bu21013_data->chip->cs_pin, 0);
gpio_free(bu21013_data->chip->cs_pin);
}
#ifdef CONFIG_OF
static const struct bu21013_platform_device *
bu21013_parse_dt(struct device *dev)
{
struct device_node *np = dev->of_node;
struct bu21013_platform_device *pdata;
if (!np) {
dev_err(dev, "no device tree or platform data\n");
return ERR_PTR(-EINVAL);
}
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->y_flip = pdata->x_flip = false;
pdata->x_flip = of_property_read_bool(np, "rohm,flip-x");
pdata->y_flip = of_property_read_bool(np, "rohm,flip-y");
of_property_read_u32(np, "rohm,touch-max-x", &pdata->touch_x_max);
of_property_read_u32(np, "rohm,touch-max-y", &pdata->touch_y_max);
pdata->touch_pin = of_get_named_gpio(np, "touch-gpio", 0);
pdata->cs_pin = of_get_named_gpio(np, "reset-gpio", 0);
pdata->ext_clk = false;
return pdata;
}
#else
static inline const struct bu21013_platform_device *
bu21013_parse_dt(struct device *dev)
{
dev_err(dev, "no platform data available\n");
return ERR_PTR(-EINVAL);
}
#endif
/**
* bu21013_probe() - initializes the i2c-client touchscreen driver
* @client: i2c client structure pointer
* @id: i2c device id pointer
*
* This function used to initializes the i2c-client touchscreen
* driver and returns integer.
*/
static int bu21013_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct bu21013_platform_device *pdata =
dev_get_platdata(&client->dev);
struct bu21013_ts_data *bu21013_data;
struct input_dev *in_dev;
int error;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev, "i2c smbus byte data not supported\n");
return -EIO;
}
if (!pdata) {
pdata = bu21013_parse_dt(&client->dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
if (!gpio_is_valid(pdata->touch_pin)) {
dev_err(&client->dev, "invalid touch_pin supplied\n");
return -EINVAL;
}
bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL);
in_dev = input_allocate_device();
if (!bu21013_data || !in_dev) {
dev_err(&client->dev, "device memory alloc failed\n");
error = -ENOMEM;
goto err_free_mem;
}
bu21013_data->in_dev = in_dev;
bu21013_data->chip = pdata;
bu21013_data->client = client;
bu21013_data->irq = gpio_to_irq(pdata->touch_pin);
bu21013_data->regulator = regulator_get(&client->dev, "avdd");
if (IS_ERR(bu21013_data->regulator)) {
dev_err(&client->dev, "regulator_get failed\n");
error = PTR_ERR(bu21013_data->regulator);
goto err_free_mem;
}
error = regulator_enable(bu21013_data->regulator);
if (error < 0) {
dev_err(&client->dev, "regulator enable failed\n");
goto err_put_regulator;
}
bu21013_data->touch_stopped = false;
init_waitqueue_head(&bu21013_data->wait);
/* configure the gpio pins */
error = gpio_request_one(pdata->cs_pin, GPIOF_OUT_INIT_HIGH,
"touchp_reset");
if (error < 0) {
dev_err(&client->dev, "Unable to request gpio reset_pin\n");
goto err_disable_regulator;
}
/* configure the touch panel controller */
error = bu21013_init_chip(bu21013_data);
if (error) {
dev_err(&client->dev, "error in bu21013 config\n");
goto err_cs_disable;
}
/* register the device to input subsystem */
in_dev->name = DRIVER_TP;
in_dev->id.bustype = BUS_I2C;
in_dev->dev.parent = &client->dev;
__set_bit(EV_SYN, in_dev->evbit);
__set_bit(EV_KEY, in_dev->evbit);
__set_bit(EV_ABS, in_dev->evbit);
input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,
pdata->touch_x_max, 0, 0);
input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,
pdata->touch_y_max, 0, 0);
input_set_drvdata(in_dev, bu21013_data);
error = request_threaded_irq(bu21013_data->irq, NULL, bu21013_gpio_irq,
IRQF_TRIGGER_FALLING | IRQF_SHARED |
IRQF_ONESHOT,
DRIVER_TP, bu21013_data);
if (error) {
dev_err(&client->dev, "request irq %d failed\n",
bu21013_data->irq);
goto err_cs_disable;
}
error = input_register_device(in_dev);
if (error) {
dev_err(&client->dev, "failed to register input device\n");
goto err_free_irq;
}
device_init_wakeup(&client->dev, pdata->wakeup);
i2c_set_clientdata(client, bu21013_data);
return 0;
err_free_irq:
bu21013_free_irq(bu21013_data);
err_cs_disable:
bu21013_cs_disable(bu21013_data);
err_disable_regulator:
regulator_disable(bu21013_data->regulator);
err_put_regulator:
regulator_put(bu21013_data->regulator);
err_free_mem:
input_free_device(in_dev);
kfree(bu21013_data);
return error;
}
/**
* bu21013_remove() - removes the i2c-client touchscreen driver
* @client: i2c client structure pointer
*
* This function uses to remove the i2c-client
* touchscreen driver and returns integer.
*/
static int bu21013_remove(struct i2c_client *client)
{
struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
bu21013_free_irq(bu21013_data);
bu21013_cs_disable(bu21013_data);
input_unregister_device(bu21013_data->in_dev);
regulator_disable(bu21013_data->regulator);
regulator_put(bu21013_data->regulator);
kfree(bu21013_data);
device_init_wakeup(&client->dev, false);
return 0;
}
#ifdef CONFIG_PM
/**
* bu21013_suspend() - suspend the touch screen controller
* @dev: pointer to device structure
*
* This function is used to suspend the
* touch panel controller and returns integer
*/
static int bu21013_suspend(struct device *dev)
{
struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
struct i2c_client *client = bu21013_data->client;
bu21013_data->touch_stopped = true;
if (device_may_wakeup(&client->dev))
enable_irq_wake(bu21013_data->irq);
else
disable_irq(bu21013_data->irq);
regulator_disable(bu21013_data->regulator);
return 0;
}
/**
* bu21013_resume() - resume the touch screen controller
* @dev: pointer to device structure
*
* This function is used to resume the touch panel
* controller and returns integer.
*/
static int bu21013_resume(struct device *dev)
{
struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
struct i2c_client *client = bu21013_data->client;
int retval;
retval = regulator_enable(bu21013_data->regulator);
if (retval < 0) {
dev_err(&client->dev, "bu21013 regulator enable failed\n");
return retval;
}
retval = bu21013_init_chip(bu21013_data);
if (retval < 0) {
dev_err(&client->dev, "bu21013 controller config failed\n");
return retval;
}
bu21013_data->touch_stopped = false;
if (device_may_wakeup(&client->dev))
disable_irq_wake(bu21013_data->irq);
else
enable_irq(bu21013_data->irq);
return 0;
}
static const struct dev_pm_ops bu21013_dev_pm_ops = {
.suspend = bu21013_suspend,
.resume = bu21013_resume,
};
#endif
static const struct i2c_device_id bu21013_id[] = {
{ DRIVER_TP, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bu21013_id);
static struct i2c_driver bu21013_driver = {
.driver = {
.name = DRIVER_TP,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &bu21013_dev_pm_ops,
#endif
},
.probe = bu21013_probe,
.remove = bu21013_remove,
.id_table = bu21013_id,
};
module_i2c_driver(bu21013_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>");
MODULE_DESCRIPTION("bu21013 touch screen controller driver");

View file

@ -0,0 +1,365 @@
/*
* Driver for cypress touch screen controller
*
* Copyright (c) 2009 Aava Mobile
*
* Some cleanups by Alan Cox <alan@linux.intel.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.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/input/cy8ctmg110_pdata.h>
#define CY8CTMG110_DRIVER_NAME "cy8ctmg110"
/* Touch coordinates */
#define CY8CTMG110_X_MIN 0
#define CY8CTMG110_Y_MIN 0
#define CY8CTMG110_X_MAX 759
#define CY8CTMG110_Y_MAX 465
/* cy8ctmg110 register definitions */
#define CY8CTMG110_TOUCH_WAKEUP_TIME 0
#define CY8CTMG110_TOUCH_SLEEP_TIME 2
#define CY8CTMG110_TOUCH_X1 3
#define CY8CTMG110_TOUCH_Y1 5
#define CY8CTMG110_TOUCH_X2 7
#define CY8CTMG110_TOUCH_Y2 9
#define CY8CTMG110_FINGERS 11
#define CY8CTMG110_GESTURE 12
#define CY8CTMG110_REG_MAX 13
/*
* The touch driver structure.
*/
struct cy8ctmg110 {
struct input_dev *input;
char phys[32];
struct i2c_client *client;
int reset_pin;
int irq_pin;
};
/*
* cy8ctmg110_power is the routine that is called when touch hardware
* will powered off or on.
*/
static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron)
{
if (ts->reset_pin)
gpio_direction_output(ts->reset_pin, 1 - poweron);
}
static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
unsigned char len, unsigned char *value)
{
struct i2c_client *client = tsc->client;
int ret;
unsigned char i2c_data[6];
BUG_ON(len > 5);
i2c_data[0] = reg;
memcpy(i2c_data + 1, value, len);
ret = i2c_master_send(client, i2c_data, len + 1);
if (ret != len + 1) {
dev_err(&client->dev, "i2c write data cmd failed\n");
return ret < 0 ? ret : -EIO;
}
return 0;
}
static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc,
unsigned char *data, unsigned char len, unsigned char cmd)
{
struct i2c_client *client = tsc->client;
int ret;
struct i2c_msg msg[2] = {
/* first write slave position to i2c devices */
{
.addr = client->addr,
.len = 1,
.buf = &cmd
},
/* Second read data from position */
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = data
}
};
ret = i2c_transfer(client->adapter, msg, 2);
if (ret < 0)
return ret;
return 0;
}
static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
{
struct input_dev *input = tsc->input;
unsigned char reg_p[CY8CTMG110_REG_MAX];
int x, y;
memset(reg_p, 0, CY8CTMG110_REG_MAX);
/* Reading coordinates */
if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
return -EIO;
y = reg_p[2] << 8 | reg_p[3];
x = reg_p[0] << 8 | reg_p[1];
/* Number of touch */
if (reg_p[8] == 0) {
input_report_key(input, BTN_TOUCH, 0);
} else {
input_report_key(input, BTN_TOUCH, 1);
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
}
input_sync(input);
return 0;
}
static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep)
{
unsigned char reg_p[3];
if (sleep) {
reg_p[0] = 0x00;
reg_p[1] = 0xff;
reg_p[2] = 5;
} else {
reg_p[0] = 0x10;
reg_p[1] = 0xff;
reg_p[2] = 0;
}
return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p);
}
static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
{
struct cy8ctmg110 *tsc = dev_id;
cy8ctmg110_touch_pos(tsc);
return IRQ_HANDLED;
}
static int cy8ctmg110_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct cy8ctmg110_pdata *pdata = dev_get_platdata(&client->dev);
struct cy8ctmg110 *ts;
struct input_dev *input_dev;
int err;
/* No pdata no way forward */
if (pdata == NULL) {
dev_err(&client->dev, "no pdata\n");
return -ENODEV;
}
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_WORD_DATA))
return -EIO;
ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
ts->client = client;
ts->input = input_dev;
ts->reset_pin = pdata->reset_pin;
ts->irq_pin = pdata->irq_pin;
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
input_dev->phys = ts->phys;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X,
CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
input_set_abs_params(input_dev, ABS_Y,
CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
if (ts->reset_pin) {
err = gpio_request(ts->reset_pin, NULL);
if (err) {
dev_err(&client->dev,
"Unable to request GPIO pin %d.\n",
ts->reset_pin);
goto err_free_mem;
}
}
cy8ctmg110_power(ts, true);
cy8ctmg110_set_sleepmode(ts, false);
err = gpio_request(ts->irq_pin, "touch_irq_key");
if (err < 0) {
dev_err(&client->dev,
"Failed to request GPIO %d, error %d\n",
ts->irq_pin, err);
goto err_shutoff_device;
}
err = gpio_direction_input(ts->irq_pin);
if (err < 0) {
dev_err(&client->dev,
"Failed to configure input direction for GPIO %d, error %d\n",
ts->irq_pin, err);
goto err_free_irq_gpio;
}
client->irq = gpio_to_irq(ts->irq_pin);
if (client->irq < 0) {
err = client->irq;
dev_err(&client->dev,
"Unable to get irq number for GPIO %d, error %d\n",
ts->irq_pin, err);
goto err_free_irq_gpio;
}
err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"touch_reset_key", ts);
if (err < 0) {
dev_err(&client->dev,
"irq %d busy? error %d\n", client->irq, err);
goto err_free_irq_gpio;
}
err = input_register_device(input_dev);
if (err)
goto err_free_irq;
i2c_set_clientdata(client, ts);
device_init_wakeup(&client->dev, 1);
return 0;
err_free_irq:
free_irq(client->irq, ts);
err_free_irq_gpio:
gpio_free(ts->irq_pin);
err_shutoff_device:
cy8ctmg110_set_sleepmode(ts, true);
cy8ctmg110_power(ts, false);
if (ts->reset_pin)
gpio_free(ts->reset_pin);
err_free_mem:
input_free_device(input_dev);
kfree(ts);
return err;
}
#ifdef CONFIG_PM_SLEEP
static int cy8ctmg110_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
else {
cy8ctmg110_set_sleepmode(ts, true);
cy8ctmg110_power(ts, false);
}
return 0;
}
static int cy8ctmg110_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq);
else {
cy8ctmg110_power(ts, true);
cy8ctmg110_set_sleepmode(ts, false);
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
static int cy8ctmg110_remove(struct i2c_client *client)
{
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
cy8ctmg110_set_sleepmode(ts, true);
cy8ctmg110_power(ts, false);
free_irq(client->irq, ts);
input_unregister_device(ts->input);
gpio_free(ts->irq_pin);
if (ts->reset_pin)
gpio_free(ts->reset_pin);
kfree(ts);
return 0;
}
static const struct i2c_device_id cy8ctmg110_idtable[] = {
{ CY8CTMG110_DRIVER_NAME, 1 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
static struct i2c_driver cy8ctmg110_driver = {
.driver = {
.owner = THIS_MODULE,
.name = CY8CTMG110_DRIVER_NAME,
.pm = &cy8ctmg110_pm,
},
.id_table = cy8ctmg110_idtable,
.probe = cy8ctmg110_probe,
.remove = cy8ctmg110_remove,
};
module_i2c_driver(cy8ctmg110_driver);
MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,472 @@
/*
* cyttsp4_core.h
* Cypress TrueTouch(TM) Standard Product V4 Core driver module.
* For use with Cypress Txx4xx parts.
* Supported parts include:
* TMA4XX
* TMA1036
*
* Copyright (C) 2012 Cypress Semiconductor
*
* 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#ifndef _LINUX_CYTTSP4_CORE_H
#define _LINUX_CYTTSP4_CORE_H
#include <linux/device.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/stringify.h>
#include <linux/types.h>
#include <linux/platform_data/cyttsp4.h>
#define CY_REG_BASE 0x00
#define CY_POST_CODEL_WDG_RST 0x01
#define CY_POST_CODEL_CFG_DATA_CRC_FAIL 0x02
#define CY_POST_CODEL_PANEL_TEST_FAIL 0x04
#define CY_NUM_BTN_PER_REG 4
/* touch record system information offset masks and shifts */
#define CY_BYTE_OFS_MASK 0x1F
#define CY_BOFS_MASK 0xE0
#define CY_BOFS_SHIFT 5
#define CY_TMA1036_TCH_REC_SIZE 6
#define CY_TMA4XX_TCH_REC_SIZE 9
#define CY_TMA1036_MAX_TCH 0x0E
#define CY_TMA4XX_MAX_TCH 0x1E
#define CY_NORMAL_ORIGIN 0 /* upper, left corner */
#define CY_INVERT_ORIGIN 1 /* lower, right corner */
/* helpers */
#define GET_NUM_TOUCHES(x) ((x) & 0x1F)
#define IS_LARGE_AREA(x) ((x) & 0x20)
#define IS_BAD_PKT(x) ((x) & 0x20)
#define IS_BOOTLOADER(hst_mode, reset_detect) \
((hst_mode) & 0x01 || (reset_detect) != 0)
#define IS_TMO(t) ((t) == 0)
enum cyttsp_cmd_bits {
CY_CMD_COMPLETE = (1 << 6),
};
/* Timeout in ms. */
#define CY_WATCHDOG_TIMEOUT 1000
#define CY_MAX_PRINT_SIZE 512
#ifdef VERBOSE_DEBUG
#define CY_MAX_PRBUF_SIZE PIPE_BUF
#define CY_PR_TRUNCATED " truncated..."
#endif
enum cyttsp4_ic_grpnum {
CY_IC_GRPNUM_RESERVED,
CY_IC_GRPNUM_CMD_REGS,
CY_IC_GRPNUM_TCH_REP,
CY_IC_GRPNUM_DATA_REC,
CY_IC_GRPNUM_TEST_REC,
CY_IC_GRPNUM_PCFG_REC,
CY_IC_GRPNUM_TCH_PARM_VAL,
CY_IC_GRPNUM_TCH_PARM_SIZE,
CY_IC_GRPNUM_RESERVED1,
CY_IC_GRPNUM_RESERVED2,
CY_IC_GRPNUM_OPCFG_REC,
CY_IC_GRPNUM_DDATA_REC,
CY_IC_GRPNUM_MDATA_REC,
CY_IC_GRPNUM_TEST_REGS,
CY_IC_GRPNUM_BTN_KEYS,
CY_IC_GRPNUM_TTHE_REGS,
CY_IC_GRPNUM_NUM
};
enum cyttsp4_int_state {
CY_INT_NONE,
CY_INT_IGNORE = (1 << 0),
CY_INT_MODE_CHANGE = (1 << 1),
CY_INT_EXEC_CMD = (1 << 2),
CY_INT_AWAKE = (1 << 3),
};
enum cyttsp4_mode {
CY_MODE_UNKNOWN,
CY_MODE_BOOTLOADER = (1 << 1),
CY_MODE_OPERATIONAL = (1 << 2),
CY_MODE_SYSINFO = (1 << 3),
CY_MODE_CAT = (1 << 4),
CY_MODE_STARTUP = (1 << 5),
CY_MODE_LOADER = (1 << 6),
CY_MODE_CHANGE_MODE = (1 << 7),
CY_MODE_CHANGED = (1 << 8),
CY_MODE_CMD_COMPLETE = (1 << 9),
};
enum cyttsp4_sleep_state {
SS_SLEEP_OFF,
SS_SLEEP_ON,
SS_SLEEPING,
SS_WAKING,
};
enum cyttsp4_startup_state {
STARTUP_NONE,
STARTUP_QUEUED,
STARTUP_RUNNING,
};
#define CY_NUM_REVCTRL 8
struct cyttsp4_cydata {
u8 ttpidh;
u8 ttpidl;
u8 fw_ver_major;
u8 fw_ver_minor;
u8 revctrl[CY_NUM_REVCTRL];
u8 blver_major;
u8 blver_minor;
u8 jtag_si_id3;
u8 jtag_si_id2;
u8 jtag_si_id1;
u8 jtag_si_id0;
u8 mfgid_sz;
u8 cyito_idh;
u8 cyito_idl;
u8 cyito_verh;
u8 cyito_verl;
u8 ttsp_ver_major;
u8 ttsp_ver_minor;
u8 device_info;
u8 mfg_id[];
} __packed;
struct cyttsp4_test {
u8 post_codeh;
u8 post_codel;
} __packed;
struct cyttsp4_pcfg {
u8 electrodes_x;
u8 electrodes_y;
u8 len_xh;
u8 len_xl;
u8 len_yh;
u8 len_yl;
u8 res_xh;
u8 res_xl;
u8 res_yh;
u8 res_yl;
u8 max_zh;
u8 max_zl;
u8 panel_info0;
} __packed;
struct cyttsp4_tch_rec_params {
u8 loc;
u8 size;
} __packed;
#define CY_NUM_TCH_FIELDS 7
#define CY_NUM_EXT_TCH_FIELDS 3
struct cyttsp4_opcfg {
u8 cmd_ofs;
u8 rep_ofs;
u8 rep_szh;
u8 rep_szl;
u8 num_btns;
u8 tt_stat_ofs;
u8 obj_cfg0;
u8 max_tchs;
u8 tch_rec_size;
struct cyttsp4_tch_rec_params tch_rec_old[CY_NUM_TCH_FIELDS];
u8 btn_rec_size; /* btn record size (in bytes) */
u8 btn_diff_ofs; /* btn data loc, diff counts */
u8 btn_diff_size; /* btn size of diff counts (in bits) */
struct cyttsp4_tch_rec_params tch_rec_new[CY_NUM_EXT_TCH_FIELDS];
} __packed;
struct cyttsp4_sysinfo_ptr {
struct cyttsp4_cydata *cydata;
struct cyttsp4_test *test;
struct cyttsp4_pcfg *pcfg;
struct cyttsp4_opcfg *opcfg;
struct cyttsp4_ddata *ddata;
struct cyttsp4_mdata *mdata;
} __packed;
struct cyttsp4_sysinfo_data {
u8 hst_mode;
u8 reserved;
u8 map_szh;
u8 map_szl;
u8 cydata_ofsh;
u8 cydata_ofsl;
u8 test_ofsh;
u8 test_ofsl;
u8 pcfg_ofsh;
u8 pcfg_ofsl;
u8 opcfg_ofsh;
u8 opcfg_ofsl;
u8 ddata_ofsh;
u8 ddata_ofsl;
u8 mdata_ofsh;
u8 mdata_ofsl;
} __packed;
enum cyttsp4_tch_abs { /* for ordering within the extracted touch data array */
CY_TCH_X, /* X */
CY_TCH_Y, /* Y */
CY_TCH_P, /* P (Z) */
CY_TCH_T, /* TOUCH ID */
CY_TCH_E, /* EVENT ID */
CY_TCH_O, /* OBJECT ID */
CY_TCH_W, /* SIZE */
CY_TCH_MAJ, /* TOUCH_MAJOR */
CY_TCH_MIN, /* TOUCH_MINOR */
CY_TCH_OR, /* ORIENTATION */
CY_TCH_NUM_ABS
};
static const char * const cyttsp4_tch_abs_string[] = {
[CY_TCH_X] = "X",
[CY_TCH_Y] = "Y",
[CY_TCH_P] = "P",
[CY_TCH_T] = "T",
[CY_TCH_E] = "E",
[CY_TCH_O] = "O",
[CY_TCH_W] = "W",
[CY_TCH_MAJ] = "MAJ",
[CY_TCH_MIN] = "MIN",
[CY_TCH_OR] = "OR",
[CY_TCH_NUM_ABS] = "INVALID"
};
struct cyttsp4_touch {
int abs[CY_TCH_NUM_ABS];
};
struct cyttsp4_tch_abs_params {
size_t ofs; /* abs byte offset */
size_t size; /* size in bits */
size_t max; /* max value */
size_t bofs; /* bit offset */
};
struct cyttsp4_sysinfo_ofs {
size_t chip_type;
size_t cmd_ofs;
size_t rep_ofs;
size_t rep_sz;
size_t num_btns;
size_t num_btn_regs; /* ceil(num_btns/4) */
size_t tt_stat_ofs;
size_t tch_rec_size;
size_t obj_cfg0;
size_t max_tchs;
size_t mode_size;
size_t data_size;
size_t map_sz;
size_t max_x;
size_t x_origin; /* left or right corner */
size_t max_y;
size_t y_origin; /* upper or lower corner */
size_t max_p;
size_t cydata_ofs;
size_t test_ofs;
size_t pcfg_ofs;
size_t opcfg_ofs;
size_t ddata_ofs;
size_t mdata_ofs;
size_t cydata_size;
size_t test_size;
size_t pcfg_size;
size_t opcfg_size;
size_t ddata_size;
size_t mdata_size;
size_t btn_keys_size;
struct cyttsp4_tch_abs_params tch_abs[CY_TCH_NUM_ABS];
size_t btn_rec_size; /* btn record size (in bytes) */
size_t btn_diff_ofs;/* btn data loc ,diff counts, (Op-Mode byte ofs) */
size_t btn_diff_size;/* btn size of diff counts (in bits) */
};
enum cyttsp4_btn_state {
CY_BTN_RELEASED,
CY_BTN_PRESSED,
CY_BTN_NUM_STATE
};
struct cyttsp4_btn {
bool enabled;
int state; /* CY_BTN_PRESSED, CY_BTN_RELEASED */
int key_code;
};
struct cyttsp4_sysinfo {
bool ready;
struct cyttsp4_sysinfo_data si_data;
struct cyttsp4_sysinfo_ptr si_ptrs;
struct cyttsp4_sysinfo_ofs si_ofs;
struct cyttsp4_btn *btn; /* button states */
u8 *btn_rec_data; /* button diff count data */
u8 *xy_mode; /* operational mode and status regs */
u8 *xy_data; /* operational touch regs */
};
struct cyttsp4_mt_data {
struct cyttsp4_mt_platform_data *pdata;
struct cyttsp4_sysinfo *si;
struct input_dev *input;
struct mutex report_lock;
bool is_suspended;
char phys[NAME_MAX];
int num_prv_tch;
};
struct cyttsp4 {
struct device *dev;
struct mutex system_lock;
struct mutex adap_lock;
enum cyttsp4_mode mode;
enum cyttsp4_sleep_state sleep_state;
enum cyttsp4_startup_state startup_state;
int int_status;
wait_queue_head_t wait_q;
int irq;
struct work_struct startup_work;
struct work_struct watchdog_work;
struct timer_list watchdog_timer;
struct cyttsp4_sysinfo sysinfo;
void *exclusive_dev;
int exclusive_waits;
atomic_t ignore_irq;
bool invalid_touch_app;
struct cyttsp4_mt_data md;
struct cyttsp4_platform_data *pdata;
struct cyttsp4_core_platform_data *cpdata;
const struct cyttsp4_bus_ops *bus_ops;
u8 *xfer_buf;
#ifdef VERBOSE_DEBUG
u8 pr_buf[CY_MAX_PRBUF_SIZE];
#endif
};
struct cyttsp4_bus_ops {
u16 bustype;
int (*write)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
const void *values);
int (*read)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
void *values);
};
enum cyttsp4_hst_mode_bits {
CY_HST_TOGGLE = (1 << 7),
CY_HST_MODE_CHANGE = (1 << 3),
CY_HST_MODE = (7 << 4),
CY_HST_OPERATE = (0 << 4),
CY_HST_SYSINFO = (1 << 4),
CY_HST_CAT = (2 << 4),
CY_HST_LOWPOW = (1 << 2),
CY_HST_SLEEP = (1 << 1),
CY_HST_RESET = (1 << 0),
};
/* abs settings */
#define CY_IGNORE_VALUE 0xFFFF
/* abs signal capabilities offsets in the frameworks array */
enum cyttsp4_sig_caps {
CY_SIGNAL_OST,
CY_MIN_OST,
CY_MAX_OST,
CY_FUZZ_OST,
CY_FLAT_OST,
CY_NUM_ABS_SET /* number of signal capability fields */
};
/* abs axis signal offsets in the framworks array */
enum cyttsp4_sig_ost {
CY_ABS_X_OST,
CY_ABS_Y_OST,
CY_ABS_P_OST,
CY_ABS_W_OST,
CY_ABS_ID_OST,
CY_ABS_MAJ_OST,
CY_ABS_MIN_OST,
CY_ABS_OR_OST,
CY_NUM_ABS_OST /* number of abs signals */
};
enum cyttsp4_flags {
CY_FLAG_NONE = 0x00,
CY_FLAG_HOVER = 0x04,
CY_FLAG_FLIP = 0x08,
CY_FLAG_INV_X = 0x10,
CY_FLAG_INV_Y = 0x20,
CY_FLAG_VKEYS = 0x40,
};
enum cyttsp4_object_id {
CY_OBJ_STANDARD_FINGER,
CY_OBJ_LARGE_OBJECT,
CY_OBJ_STYLUS,
CY_OBJ_HOVER,
};
enum cyttsp4_event_id {
CY_EV_NO_EVENT,
CY_EV_TOUCHDOWN,
CY_EV_MOVE, /* significant displacement (> act dist) */
CY_EV_LIFTOFF, /* record reports last position */
};
/* x-axis resolution of panel in pixels */
#define CY_PCFG_RESOLUTION_X_MASK 0x7F
/* y-axis resolution of panel in pixels */
#define CY_PCFG_RESOLUTION_Y_MASK 0x7F
/* x-axis, 0:origin is on left side of panel, 1: right */
#define CY_PCFG_ORIGIN_X_MASK 0x80
/* y-axis, 0:origin is on top side of panel, 1: bottom */
#define CY_PCFG_ORIGIN_Y_MASK 0x80
static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u16 addr, int size,
void *buf)
{
return ts->bus_ops->read(ts->dev, ts->xfer_buf, addr, size, buf);
}
static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u16 addr, int size,
const void *buf)
{
return ts->bus_ops->write(ts->dev, ts->xfer_buf, addr, size, buf);
}
extern struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
struct device *dev, u16 irq, size_t xfer_buf_size);
extern int cyttsp4_remove(struct cyttsp4 *ts);
int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
u8 length, const void *values);
int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
u8 length, void *values);
extern const struct dev_pm_ops cyttsp4_pm_ops;
#endif /* _LINUX_CYTTSP4_CORE_H */

View file

@ -0,0 +1,90 @@
/*
* cyttsp_i2c.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
* For use with Cypress Txx4xx parts.
* Supported parts include:
* TMA4XX
* TMA1036
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
* 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#include "cyttsp4_core.h"
#include <linux/i2c.h>
#include <linux/input.h>
#define CYTTSP4_I2C_DATA_SIZE (3 * 256)
static const struct cyttsp4_bus_ops cyttsp4_i2c_bus_ops = {
.bustype = BUS_I2C,
.write = cyttsp_i2c_write_block_data,
.read = cyttsp_i2c_read_block_data,
};
static int cyttsp4_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct cyttsp4 *ts;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "I2C functionality not Supported\n");
return -EIO;
}
ts = cyttsp4_probe(&cyttsp4_i2c_bus_ops, &client->dev, client->irq,
CYTTSP4_I2C_DATA_SIZE);
if (IS_ERR(ts))
return PTR_ERR(ts);
return 0;
}
static int cyttsp4_i2c_remove(struct i2c_client *client)
{
struct cyttsp4 *ts = i2c_get_clientdata(client);
cyttsp4_remove(ts);
return 0;
}
static const struct i2c_device_id cyttsp4_i2c_id[] = {
{ CYTTSP4_I2C_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id);
static struct i2c_driver cyttsp4_i2c_driver = {
.driver = {
.name = CYTTSP4_I2C_NAME,
.owner = THIS_MODULE,
.pm = &cyttsp4_pm_ops,
},
.probe = cyttsp4_i2c_probe,
.remove = cyttsp4_i2c_remove,
.id_table = cyttsp4_i2c_id,
};
module_i2c_driver(cyttsp4_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
MODULE_AUTHOR("Cypress");
MODULE_ALIAS("i2c:cyttsp4");

View file

@ -0,0 +1,200 @@
/*
* Source for:
* Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
* For use with Cypress Txx4xx parts.
* Supported parts include:
* TMA4XX
* TMA1036
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
* 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#include "cyttsp4_core.h"
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
#define CY_SPI_WR_OP 0x00 /* r/~w */
#define CY_SPI_RD_OP 0x01
#define CY_SPI_BITS_PER_WORD 8
#define CY_SPI_A8_BIT 0x02
#define CY_SPI_WR_HEADER_BYTES 2
#define CY_SPI_RD_HEADER_BYTES 1
#define CY_SPI_CMD_BYTES 2
#define CY_SPI_SYNC_BYTE 0
#define CY_SPI_SYNC_ACK 0x62 /* from TRM *A protocol */
#define CY_SPI_DATA_SIZE (2 * 256)
#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
u8 op, u16 reg, u8 *buf, int length)
{
struct spi_device *spi = to_spi_device(dev);
struct spi_message msg;
struct spi_transfer xfer[2];
u8 *wr_buf = &xfer_buf[0];
u8 rd_buf[CY_SPI_CMD_BYTES];
int retval;
int i;
if (length > CY_SPI_DATA_SIZE) {
dev_err(dev, "%s: length %d is too big.\n",
__func__, length);
return -EINVAL;
}
memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
memset(rd_buf, 0, CY_SPI_CMD_BYTES);
wr_buf[0] = op + (((reg >> 8) & 0x1) ? CY_SPI_A8_BIT : 0);
if (op == CY_SPI_WR_OP) {
wr_buf[1] = reg & 0xFF;
if (length > 0)
memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
}
memset(xfer, 0, sizeof(xfer));
spi_message_init(&msg);
/*
We set both TX and RX buffers because Cypress TTSP
requires full duplex operation.
*/
xfer[0].tx_buf = wr_buf;
xfer[0].rx_buf = rd_buf;
switch (op) {
case CY_SPI_WR_OP:
xfer[0].len = length + CY_SPI_CMD_BYTES;
spi_message_add_tail(&xfer[0], &msg);
break;
case CY_SPI_RD_OP:
xfer[0].len = CY_SPI_RD_HEADER_BYTES;
spi_message_add_tail(&xfer[0], &msg);
xfer[1].rx_buf = buf;
xfer[1].len = length;
spi_message_add_tail(&xfer[1], &msg);
break;
default:
dev_err(dev, "%s: bad operation code=%d\n", __func__, op);
return -EINVAL;
}
retval = spi_sync(spi, &msg);
if (retval < 0) {
dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
__func__, retval, xfer[1].len, op);
/*
* do not return here since was a bad ACK sequence
* let the following ACK check handle any errors and
* allow silent retries
*/
}
if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) {
dev_dbg(dev, "%s: operation %d failed\n", __func__, op);
for (i = 0; i < CY_SPI_CMD_BYTES; i++)
dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n",
__func__, i, rd_buf[i]);
for (i = 0; i < length; i++)
dev_dbg(dev, "%s: test buf[%d]:0x%02x\n",
__func__, i, buf[i]);
return -EIO;
}
return 0;
}
static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
u16 addr, u8 length, void *data)
{
int rc;
rc = cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, NULL, 0);
if (rc)
return rc;
else
return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
length);
}
static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
u16 addr, u8 length, const void *data)
{
return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
length);
}
static const struct cyttsp4_bus_ops cyttsp_spi_bus_ops = {
.bustype = BUS_SPI,
.write = cyttsp_spi_write_block_data,
.read = cyttsp_spi_read_block_data,
};
static int cyttsp4_spi_probe(struct spi_device *spi)
{
struct cyttsp4 *ts;
int error;
/* Set up SPI*/
spi->bits_per_word = CY_SPI_BITS_PER_WORD;
spi->mode = SPI_MODE_0;
error = spi_setup(spi);
if (error < 0) {
dev_err(&spi->dev, "%s: SPI setup error %d\n",
__func__, error);
return error;
}
ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
CY_SPI_DATA_BUF_SIZE);
return PTR_ERR_OR_ZERO(ts);
}
static int cyttsp4_spi_remove(struct spi_device *spi)
{
struct cyttsp4 *ts = spi_get_drvdata(spi);
cyttsp4_remove(ts);
return 0;
}
static struct spi_driver cyttsp4_spi_driver = {
.driver = {
.name = CYTTSP4_SPI_NAME,
.owner = THIS_MODULE,
.pm = &cyttsp4_pm_ops,
},
.probe = cyttsp4_spi_probe,
.remove = cyttsp4_spi_remove,
};
module_spi_driver(cyttsp4_spi_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
MODULE_AUTHOR("Cypress");
MODULE_ALIAS("spi:cyttsp4");

View file

@ -0,0 +1,641 @@
/*
* Core Source for:
* Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
* For use with Cypress Txx3xx parts.
* Supported parts include:
* CY8CTST341
* CY8CTMA340
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
*
* 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 <kev@cypress.com>
*
*/
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include "cyttsp_core.h"
/* Bootloader number of command keys */
#define CY_NUM_BL_KEYS 8
/* helpers */
#define GET_NUM_TOUCHES(x) ((x) & 0x0F)
#define IS_LARGE_AREA(x) (((x) & 0x10) >> 4)
#define IS_BAD_PKT(x) ((x) & 0x20)
#define IS_VALID_APP(x) ((x) & 0x01)
#define IS_OPERATIONAL_ERR(x) ((x) & 0x3F)
#define GET_HSTMODE(reg) (((reg) & 0x70) >> 4)
#define GET_BOOTLOADERMODE(reg) (((reg) & 0x10) >> 4)
#define CY_REG_BASE 0x00
#define CY_REG_ACT_DIST 0x1E
#define CY_REG_ACT_INTRVL 0x1D
#define CY_REG_TCH_TMOUT (CY_REG_ACT_INTRVL + 1)
#define CY_REG_LP_INTRVL (CY_REG_TCH_TMOUT + 1)
#define CY_MAXZ 255
#define CY_DELAY_DFLT 20 /* ms */
#define CY_DELAY_MAX 500
#define CY_ACT_DIST_DFLT 0xF8
#define CY_HNDSHK_BIT 0x80
/* device mode bits */
#define CY_OPERATE_MODE 0x00
#define CY_SYSINFO_MODE 0x10
/* power mode select bits */
#define CY_SOFT_RESET_MODE 0x01 /* return to Bootloader mode */
#define CY_DEEP_SLEEP_MODE 0x02
#define CY_LOW_POWER_MODE 0x04
/* Slots management */
#define CY_MAX_FINGER 4
#define CY_MAX_ID 16
static const u8 bl_command[] = {
0x00, /* file offset */
0xFF, /* command */
0xA5, /* exit bootloader command */
0, 1, 2, 3, 4, 5, 6, 7 /* default keys */
};
static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
u8 length, void *buf)
{
int error;
int tries;
for (tries = 0; tries < CY_NUM_RETRY; tries++) {
error = ts->bus_ops->read(ts->dev, ts->xfer_buf, command,
length, buf);
if (!error)
return 0;
msleep(CY_DELAY_DFLT);
}
return -EIO;
}
static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
u8 length, void *buf)
{
int error;
int tries;
for (tries = 0; tries < CY_NUM_RETRY; tries++) {
error = ts->bus_ops->write(ts->dev, ts->xfer_buf, command,
length, buf);
if (!error)
return 0;
msleep(CY_DELAY_DFLT);
}
return -EIO;
}
static int ttsp_send_command(struct cyttsp *ts, u8 cmd)
{
return ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
}
static int cyttsp_handshake(struct cyttsp *ts)
{
if (ts->pdata->use_hndshk)
return ttsp_send_command(ts,
ts->xy_data.hst_mode ^ CY_HNDSHK_BIT);
return 0;
}
static int cyttsp_load_bl_regs(struct cyttsp *ts)
{
memset(&ts->bl_data, 0, sizeof(ts->bl_data));
ts->bl_data.bl_status = 0x10;
return ttsp_read_block_data(ts, CY_REG_BASE,
sizeof(ts->bl_data), &ts->bl_data);
}
static int cyttsp_exit_bl_mode(struct cyttsp *ts)
{
int error;
u8 bl_cmd[sizeof(bl_command)];
memcpy(bl_cmd, bl_command, sizeof(bl_command));
if (ts->pdata->bl_keys)
memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
ts->pdata->bl_keys, CY_NUM_BL_KEYS);
error = ttsp_write_block_data(ts, CY_REG_BASE,
sizeof(bl_cmd), bl_cmd);
if (error)
return error;
/* wait for TTSP Device to complete the operation */
msleep(CY_DELAY_DFLT);
error = cyttsp_load_bl_regs(ts);
if (error)
return error;
if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
return -EIO;
return 0;
}
static int cyttsp_set_operational_mode(struct cyttsp *ts)
{
int error;
error = ttsp_send_command(ts, CY_OPERATE_MODE);
if (error)
return error;
/* wait for TTSP Device to complete switch to Operational mode */
error = ttsp_read_block_data(ts, CY_REG_BASE,
sizeof(ts->xy_data), &ts->xy_data);
if (error)
return error;
error = cyttsp_handshake(ts);
if (error)
return error;
return ts->xy_data.act_dist == CY_ACT_DIST_DFLT ? -EIO : 0;
}
static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
{
int error;
memset(&ts->sysinfo_data, 0, sizeof(ts->sysinfo_data));
/* switch to sysinfo mode */
error = ttsp_send_command(ts, CY_SYSINFO_MODE);
if (error)
return error;
/* read sysinfo registers */
msleep(CY_DELAY_DFLT);
error = ttsp_read_block_data(ts, CY_REG_BASE, sizeof(ts->sysinfo_data),
&ts->sysinfo_data);
if (error)
return error;
error = cyttsp_handshake(ts);
if (error)
return error;
if (!ts->sysinfo_data.tts_verh && !ts->sysinfo_data.tts_verl)
return -EIO;
return 0;
}
static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
{
int retval = 0;
if (ts->pdata->act_intrvl != CY_ACT_INTRVL_DFLT ||
ts->pdata->tch_tmout != CY_TCH_TMOUT_DFLT ||
ts->pdata->lp_intrvl != CY_LP_INTRVL_DFLT) {
u8 intrvl_ray[] = {
ts->pdata->act_intrvl,
ts->pdata->tch_tmout,
ts->pdata->lp_intrvl
};
/* set intrvl registers */
retval = ttsp_write_block_data(ts, CY_REG_ACT_INTRVL,
sizeof(intrvl_ray), intrvl_ray);
msleep(CY_DELAY_DFLT);
}
return retval;
}
static int cyttsp_soft_reset(struct cyttsp *ts)
{
unsigned long timeout;
int retval;
/* wait for interrupt to set ready completion */
reinit_completion(&ts->bl_ready);
ts->state = CY_BL_STATE;
enable_irq(ts->irq);
retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE);
if (retval)
goto out;
timeout = wait_for_completion_timeout(&ts->bl_ready,
msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX));
retval = timeout ? 0 : -EIO;
out:
ts->state = CY_IDLE_STATE;
disable_irq(ts->irq);
return retval;
}
static int cyttsp_act_dist_setup(struct cyttsp *ts)
{
u8 act_dist_setup = ts->pdata->act_dist;
/* Init gesture; active distance setup */
return ttsp_write_block_data(ts, CY_REG_ACT_DIST,
sizeof(act_dist_setup), &act_dist_setup);
}
static void cyttsp_extract_track_ids(struct cyttsp_xydata *xy_data, int *ids)
{
ids[0] = xy_data->touch12_id >> 4;
ids[1] = xy_data->touch12_id & 0xF;
ids[2] = xy_data->touch34_id >> 4;
ids[3] = xy_data->touch34_id & 0xF;
}
static const struct cyttsp_tch *cyttsp_get_tch(struct cyttsp_xydata *xy_data,
int idx)
{
switch (idx) {
case 0:
return &xy_data->tch1;
case 1:
return &xy_data->tch2;
case 2:
return &xy_data->tch3;
case 3:
return &xy_data->tch4;
default:
return NULL;
}
}
static void cyttsp_report_tchdata(struct cyttsp *ts)
{
struct cyttsp_xydata *xy_data = &ts->xy_data;
struct input_dev *input = ts->input;
int num_tch = GET_NUM_TOUCHES(xy_data->tt_stat);
const struct cyttsp_tch *tch;
int ids[CY_MAX_ID];
int i;
DECLARE_BITMAP(used, CY_MAX_ID);
if (IS_LARGE_AREA(xy_data->tt_stat) == 1) {
/* terminate all active tracks */
num_tch = 0;
dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
} else if (num_tch > CY_MAX_FINGER) {
/* terminate all active tracks */
num_tch = 0;
dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
} else if (IS_BAD_PKT(xy_data->tt_mode)) {
/* terminate all active tracks */
num_tch = 0;
dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
}
cyttsp_extract_track_ids(xy_data, ids);
bitmap_zero(used, CY_MAX_ID);
for (i = 0; i < num_tch; i++) {
tch = cyttsp_get_tch(xy_data, i);
input_mt_slot(input, ids[i]);
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
input_report_abs(input, ABS_MT_POSITION_X, be16_to_cpu(tch->x));
input_report_abs(input, ABS_MT_POSITION_Y, be16_to_cpu(tch->y));
input_report_abs(input, ABS_MT_TOUCH_MAJOR, tch->z);
__set_bit(ids[i], used);
}
for (i = 0; i < CY_MAX_ID; i++) {
if (test_bit(i, used))
continue;
input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
}
input_sync(input);
}
static irqreturn_t cyttsp_irq(int irq, void *handle)
{
struct cyttsp *ts = handle;
int error;
if (unlikely(ts->state == CY_BL_STATE)) {
complete(&ts->bl_ready);
goto out;
}
/* Get touch data from CYTTSP device */
error = ttsp_read_block_data(ts, CY_REG_BASE,
sizeof(struct cyttsp_xydata), &ts->xy_data);
if (error)
goto out;
/* provide flow control handshake */
error = cyttsp_handshake(ts);
if (error)
goto out;
if (unlikely(ts->state == CY_IDLE_STATE))
goto out;
if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
/*
* TTSP device has reset back to bootloader mode.
* Restore to operational mode.
*/
error = cyttsp_exit_bl_mode(ts);
if (error) {
dev_err(ts->dev,
"Could not return to operational mode, err: %d\n",
error);
ts->state = CY_IDLE_STATE;
}
} else {
cyttsp_report_tchdata(ts);
}
out:
return IRQ_HANDLED;
}
static int cyttsp_power_on(struct cyttsp *ts)
{
int error;
error = cyttsp_soft_reset(ts);
if (error)
return error;
error = cyttsp_load_bl_regs(ts);
if (error)
return error;
if (GET_BOOTLOADERMODE(ts->bl_data.bl_status) &&
IS_VALID_APP(ts->bl_data.bl_status)) {
error = cyttsp_exit_bl_mode(ts);
if (error)
return error;
}
if (GET_HSTMODE(ts->bl_data.bl_file) != CY_OPERATE_MODE ||
IS_OPERATIONAL_ERR(ts->bl_data.bl_status)) {
return -ENODEV;
}
error = cyttsp_set_sysinfo_mode(ts);
if (error)
return error;
error = cyttsp_set_sysinfo_regs(ts);
if (error)
return error;
error = cyttsp_set_operational_mode(ts);
if (error)
return error;
/* init active distance */
error = cyttsp_act_dist_setup(ts);
if (error)
return error;
ts->state = CY_ACTIVE_STATE;
return 0;
}
static int cyttsp_enable(struct cyttsp *ts)
{
int error;
/*
* The device firmware can wake on an I2C or SPI memory slave
* address match. So just reading a register is sufficient to
* wake up the device. The first read attempt will fail but it
* will wake it up making the second read attempt successful.
*/
error = ttsp_read_block_data(ts, CY_REG_BASE,
sizeof(ts->xy_data), &ts->xy_data);
if (error)
return error;
if (GET_HSTMODE(ts->xy_data.hst_mode))
return -EIO;
enable_irq(ts->irq);
return 0;
}
static int cyttsp_disable(struct cyttsp *ts)
{
int error;
error = ttsp_send_command(ts, CY_LOW_POWER_MODE);
if (error)
return error;
disable_irq(ts->irq);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int cyttsp_suspend(struct device *dev)
{
struct cyttsp *ts = dev_get_drvdata(dev);
int retval = 0;
mutex_lock(&ts->input->mutex);
if (ts->input->users) {
retval = cyttsp_disable(ts);
if (retval == 0)
ts->suspended = true;
}
mutex_unlock(&ts->input->mutex);
return retval;
}
static int cyttsp_resume(struct device *dev)
{
struct cyttsp *ts = dev_get_drvdata(dev);
mutex_lock(&ts->input->mutex);
if (ts->input->users)
cyttsp_enable(ts);
ts->suspended = false;
mutex_unlock(&ts->input->mutex);
return 0;
}
#endif
SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume);
EXPORT_SYMBOL_GPL(cyttsp_pm_ops);
static int cyttsp_open(struct input_dev *dev)
{
struct cyttsp *ts = input_get_drvdata(dev);
int retval = 0;
if (!ts->suspended)
retval = cyttsp_enable(ts);
return retval;
}
static void cyttsp_close(struct input_dev *dev)
{
struct cyttsp *ts = input_get_drvdata(dev);
if (!ts->suspended)
cyttsp_disable(ts);
}
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size)
{
const struct cyttsp_platform_data *pdata = dev_get_platdata(dev);
struct cyttsp *ts;
struct input_dev *input_dev;
int error;
if (!pdata || !pdata->name || irq <= 0) {
error = -EINVAL;
goto err_out;
}
ts = kzalloc(sizeof(*ts) + xfer_buf_size, GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
error = -ENOMEM;
goto err_free_mem;
}
ts->dev = dev;
ts->input = input_dev;
ts->pdata = dev_get_platdata(dev);
ts->bus_ops = bus_ops;
ts->irq = irq;
init_completion(&ts->bl_ready);
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
if (pdata->init) {
error = pdata->init();
if (error) {
dev_err(ts->dev, "platform init failed, err: %d\n",
error);
goto err_free_mem;
}
}
input_dev->name = pdata->name;
input_dev->phys = ts->phys;
input_dev->id.bustype = bus_ops->bustype;
input_dev->dev.parent = ts->dev;
input_dev->open = cyttsp_open;
input_dev->close = cyttsp_close;
input_set_drvdata(input_dev, ts);
__set_bit(EV_ABS, input_dev->evbit);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, pdata->maxx, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, pdata->maxy, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, CY_MAXZ, 0, 0);
input_mt_init_slots(input_dev, CY_MAX_ID, 0);
error = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
pdata->name, ts);
if (error) {
dev_err(ts->dev, "failed to request IRQ %d, err: %d\n",
ts->irq, error);
goto err_platform_exit;
}
disable_irq(ts->irq);
error = cyttsp_power_on(ts);
if (error)
goto err_free_irq;
error = input_register_device(input_dev);
if (error) {
dev_err(ts->dev, "failed to register input device: %d\n",
error);
goto err_free_irq;
}
return ts;
err_free_irq:
free_irq(ts->irq, ts);
err_platform_exit:
if (pdata->exit)
pdata->exit();
err_free_mem:
input_free_device(input_dev);
kfree(ts);
err_out:
return ERR_PTR(error);
}
EXPORT_SYMBOL_GPL(cyttsp_probe);
void cyttsp_remove(struct cyttsp *ts)
{
free_irq(ts->irq, ts);
input_unregister_device(ts->input);
if (ts->pdata->exit)
ts->pdata->exit();
kfree(ts);
}
EXPORT_SYMBOL_GPL(cyttsp_remove);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
MODULE_AUTHOR("Cypress");

View file

@ -0,0 +1,154 @@
/*
* Header file for:
* Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
* For use with Cypress Txx3xx parts.
* Supported parts include:
* CY8CTST341
* CY8CTMA340
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
*
* 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 <kev@cypress.com>
*
*/
#ifndef __CYTTSP_CORE_H__
#define __CYTTSP_CORE_H__
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/input/cyttsp.h>
#define CY_NUM_RETRY 16 /* max number of retries for read ops */
struct cyttsp_tch {
__be16 x, y;
u8 z;
} __packed;
/* TrueTouch Standard Product Gen3 interface definition */
struct cyttsp_xydata {
u8 hst_mode;
u8 tt_mode;
u8 tt_stat;
struct cyttsp_tch tch1;
u8 touch12_id;
struct cyttsp_tch tch2;
u8 gest_cnt;
u8 gest_id;
struct cyttsp_tch tch3;
u8 touch34_id;
struct cyttsp_tch tch4;
u8 tt_undef[3];
u8 act_dist;
u8 tt_reserved;
} __packed;
/* TTSP System Information interface definition */
struct cyttsp_sysinfo_data {
u8 hst_mode;
u8 mfg_stat;
u8 mfg_cmd;
u8 cid[3];
u8 tt_undef1;
u8 uid[8];
u8 bl_verh;
u8 bl_verl;
u8 tts_verh;
u8 tts_verl;
u8 app_idh;
u8 app_idl;
u8 app_verh;
u8 app_verl;
u8 tt_undef[5];
u8 scn_typ;
u8 act_intrvl;
u8 tch_tmout;
u8 lp_intrvl;
};
/* TTSP Bootloader Register Map interface definition */
#define CY_BL_CHKSUM_OK 0x01
struct cyttsp_bootloader_data {
u8 bl_file;
u8 bl_status;
u8 bl_error;
u8 blver_hi;
u8 blver_lo;
u8 bld_blver_hi;
u8 bld_blver_lo;
u8 ttspver_hi;
u8 ttspver_lo;
u8 appid_hi;
u8 appid_lo;
u8 appver_hi;
u8 appver_lo;
u8 cid_0;
u8 cid_1;
u8 cid_2;
};
struct cyttsp;
struct cyttsp_bus_ops {
u16 bustype;
int (*write)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
const void *values);
int (*read)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
void *values);
};
enum cyttsp_state {
CY_IDLE_STATE,
CY_ACTIVE_STATE,
CY_BL_STATE,
};
struct cyttsp {
struct device *dev;
int irq;
struct input_dev *input;
char phys[32];
const struct cyttsp_platform_data *pdata;
const struct cyttsp_bus_ops *bus_ops;
struct cyttsp_bootloader_data bl_data;
struct cyttsp_sysinfo_data sysinfo_data;
struct cyttsp_xydata xy_data;
struct completion bl_ready;
enum cyttsp_state state;
bool suspended;
u8 xfer_buf[] ____cacheline_aligned;
};
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size);
void cyttsp_remove(struct cyttsp *ts);
int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
u8 length, const void *values);
int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
u8 length, void *values);
extern const struct dev_pm_ops cyttsp_pm_ops;
#endif /* __CYTTSP_CORE_H__ */

View file

@ -0,0 +1,90 @@
/*
* cyttsp_i2c.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
* For use with Cypress Txx3xx parts.
* Supported parts include:
* CY8CTST341
* CY8CTMA340
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
*
* 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#include "cyttsp_core.h"
#include <linux/i2c.h>
#include <linux/input.h>
#define CY_I2C_DATA_SIZE 128
static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = {
.bustype = BUS_I2C,
.write = cyttsp_i2c_write_block_data,
.read = cyttsp_i2c_read_block_data,
};
static int cyttsp_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct cyttsp *ts;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "I2C functionality not Supported\n");
return -EIO;
}
ts = cyttsp_probe(&cyttsp_i2c_bus_ops, &client->dev, client->irq,
CY_I2C_DATA_SIZE);
if (IS_ERR(ts))
return PTR_ERR(ts);
i2c_set_clientdata(client, ts);
return 0;
}
static int cyttsp_i2c_remove(struct i2c_client *client)
{
struct cyttsp *ts = i2c_get_clientdata(client);
cyttsp_remove(ts);
return 0;
}
static const struct i2c_device_id cyttsp_i2c_id[] = {
{ CY_I2C_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
static struct i2c_driver cyttsp_i2c_driver = {
.driver = {
.name = CY_I2C_NAME,
.owner = THIS_MODULE,
.pm = &cyttsp_pm_ops,
},
.probe = cyttsp_i2c_probe,
.remove = cyttsp_i2c_remove,
.id_table = cyttsp_i2c_id,
};
module_i2c_driver(cyttsp_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
MODULE_AUTHOR("Cypress");
MODULE_ALIAS("i2c:cyttsp");

View file

@ -0,0 +1,95 @@
/*
* cyttsp_i2c_common.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
* For use with Cypress Txx3xx and Txx4xx parts.
* Supported parts include:
* CY8CTST341
* CY8CTMA340
* TMA4XX
* TMA1036
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
*
* 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#include <linux/device.h>
#include <linux/export.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
#include "cyttsp4_core.h"
int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,
u16 addr, u8 length, void *values)
{
struct i2c_client *client = to_i2c_client(dev);
u8 client_addr = client->addr | ((addr >> 8) & 0x1);
u8 addr_lo = addr & 0xFF;
struct i2c_msg msgs[] = {
{
.addr = client_addr,
.flags = 0,
.len = 1,
.buf = &addr_lo,
},
{
.addr = client_addr,
.flags = I2C_M_RD,
.len = length,
.buf = values,
},
};
int retval;
retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (retval < 0)
return retval;
return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
}
EXPORT_SYMBOL_GPL(cyttsp_i2c_read_block_data);
int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf,
u16 addr, u8 length, const void *values)
{
struct i2c_client *client = to_i2c_client(dev);
u8 client_addr = client->addr | ((addr >> 8) & 0x1);
u8 addr_lo = addr & 0xFF;
struct i2c_msg msgs[] = {
{
.addr = client_addr,
.flags = 0,
.len = length + 1,
.buf = xfer_buf,
},
};
int retval;
xfer_buf[0] = addr_lo;
memcpy(&xfer_buf[1], values, length);
retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (retval < 0)
return retval;
return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
}
EXPORT_SYMBOL_GPL(cyttsp_i2c_write_block_data);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cypress");

View file

@ -0,0 +1,197 @@
/*
* Source for:
* Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
* For use with Cypress Txx3xx parts.
* Supported parts include:
* CY8CTST341
* CY8CTMA340
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
* 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#include "cyttsp_core.h"
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
#define CY_SPI_WR_OP 0x00 /* r/~w */
#define CY_SPI_RD_OP 0x01
#define CY_SPI_CMD_BYTES 4
#define CY_SPI_SYNC_BYTE 2
#define CY_SPI_SYNC_ACK1 0x62 /* from protocol v.2 */
#define CY_SPI_SYNC_ACK2 0x9D /* from protocol v.2 */
#define CY_SPI_DATA_SIZE 128
#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
#define CY_SPI_BITS_PER_WORD 8
static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
u8 op, u16 reg, u8 *buf, int length)
{
struct spi_device *spi = to_spi_device(dev);
struct spi_message msg;
struct spi_transfer xfer[2];
u8 *wr_buf = &xfer_buf[0];
u8 *rd_buf = &xfer_buf[CY_SPI_DATA_BUF_SIZE];
int retval;
int i;
if (length > CY_SPI_DATA_SIZE) {
dev_err(dev, "%s: length %d is too big.\n",
__func__, length);
return -EINVAL;
}
memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
memset(rd_buf, 0, CY_SPI_DATA_BUF_SIZE);
wr_buf[0] = 0x00; /* header byte 0 */
wr_buf[1] = 0xFF; /* header byte 1 */
wr_buf[2] = reg; /* reg index */
wr_buf[3] = op; /* r/~w */
if (op == CY_SPI_WR_OP)
memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
memset(xfer, 0, sizeof(xfer));
spi_message_init(&msg);
/*
We set both TX and RX buffers because Cypress TTSP
requires full duplex operation.
*/
xfer[0].tx_buf = wr_buf;
xfer[0].rx_buf = rd_buf;
switch (op) {
case CY_SPI_WR_OP:
xfer[0].len = length + CY_SPI_CMD_BYTES;
spi_message_add_tail(&xfer[0], &msg);
break;
case CY_SPI_RD_OP:
xfer[0].len = CY_SPI_CMD_BYTES;
spi_message_add_tail(&xfer[0], &msg);
xfer[1].rx_buf = buf;
xfer[1].len = length;
spi_message_add_tail(&xfer[1], &msg);
break;
default:
dev_err(dev, "%s: bad operation code=%d\n", __func__, op);
return -EINVAL;
}
retval = spi_sync(spi, &msg);
if (retval < 0) {
dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
__func__, retval, xfer[1].len, op);
/*
* do not return here since was a bad ACK sequence
* let the following ACK check handle any errors and
* allow silent retries
*/
}
if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 ||
rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) {
dev_dbg(dev, "%s: operation %d failed\n", __func__, op);
for (i = 0; i < CY_SPI_CMD_BYTES; i++)
dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n",
__func__, i, rd_buf[i]);
for (i = 0; i < length; i++)
dev_dbg(dev, "%s: test buf[%d]:0x%02x\n",
__func__, i, buf[i]);
return -EIO;
}
return 0;
}
static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
u16 addr, u8 length, void *data)
{
return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
length);
}
static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
u16 addr, u8 length, const void *data)
{
return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
length);
}
static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = {
.bustype = BUS_SPI,
.write = cyttsp_spi_write_block_data,
.read = cyttsp_spi_read_block_data,
};
static int cyttsp_spi_probe(struct spi_device *spi)
{
struct cyttsp *ts;
int error;
/* Set up SPI*/
spi->bits_per_word = CY_SPI_BITS_PER_WORD;
spi->mode = SPI_MODE_0;
error = spi_setup(spi);
if (error < 0) {
dev_err(&spi->dev, "%s: SPI setup error %d\n",
__func__, error);
return error;
}
ts = cyttsp_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
CY_SPI_DATA_BUF_SIZE * 2);
if (IS_ERR(ts))
return PTR_ERR(ts);
spi_set_drvdata(spi, ts);
return 0;
}
static int cyttsp_spi_remove(struct spi_device *spi)
{
struct cyttsp *ts = spi_get_drvdata(spi);
cyttsp_remove(ts);
return 0;
}
static struct spi_driver cyttsp_spi_driver = {
.driver = {
.name = CY_SPI_NAME,
.owner = THIS_MODULE,
.pm = &cyttsp_pm_ops,
},
.probe = cyttsp_spi_probe,
.remove = cyttsp_spi_remove,
};
module_spi_driver(cyttsp_spi_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
MODULE_AUTHOR("Cypress");
MODULE_ALIAS("spi:cyttsp");

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,369 @@
/*
* Touchscreen driver for Dialog Semiconductor DA9034
*
* Copyright (C) 2006-2008 Marvell International Ltd.
* Fengwei Yin <fengwei.yin@marvell.com>
* Bin Yang <bin.yang@marvell.com>
* Eric Miao <eric.miao@marvell.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/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/mfd/da903x.h>
#include <linux/slab.h>
#define DA9034_MANUAL_CTRL 0x50
#define DA9034_LDO_ADC_EN (1 << 4)
#define DA9034_AUTO_CTRL1 0x51
#define DA9034_AUTO_CTRL2 0x52
#define DA9034_AUTO_TSI_EN (1 << 3)
#define DA9034_PEN_DETECT (1 << 4)
#define DA9034_TSI_CTRL1 0x53
#define DA9034_TSI_CTRL2 0x54
#define DA9034_TSI_X_MSB 0x6c
#define DA9034_TSI_Y_MSB 0x6d
#define DA9034_TSI_XY_LSB 0x6e
enum {
STATE_IDLE, /* wait for pendown */
STATE_BUSY, /* TSI busy sampling */
STATE_STOP, /* sample available */
STATE_WAIT, /* Wait to start next sample */
};
enum {
EVENT_PEN_DOWN,
EVENT_PEN_UP,
EVENT_TSI_READY,
EVENT_TIMEDOUT,
};
struct da9034_touch {
struct device *da9034_dev;
struct input_dev *input_dev;
struct delayed_work tsi_work;
struct notifier_block notifier;
int state;
int interval_ms;
int x_inverted;
int y_inverted;
int last_x;
int last_y;
};
static inline int is_pen_down(struct da9034_touch *touch)
{
return da903x_query_status(touch->da9034_dev, DA9034_STATUS_PEN_DOWN);
}
static inline int detect_pen_down(struct da9034_touch *touch, int on)
{
if (on)
return da903x_set_bits(touch->da9034_dev,
DA9034_AUTO_CTRL2, DA9034_PEN_DETECT);
else
return da903x_clr_bits(touch->da9034_dev,
DA9034_AUTO_CTRL2, DA9034_PEN_DETECT);
}
static int read_tsi(struct da9034_touch *touch)
{
uint8_t _x, _y, _v;
int ret;
ret = da903x_read(touch->da9034_dev, DA9034_TSI_X_MSB, &_x);
if (ret)
return ret;
ret = da903x_read(touch->da9034_dev, DA9034_TSI_Y_MSB, &_y);
if (ret)
return ret;
ret = da903x_read(touch->da9034_dev, DA9034_TSI_XY_LSB, &_v);
if (ret)
return ret;
touch->last_x = ((_x << 2) & 0x3fc) | (_v & 0x3);
touch->last_y = ((_y << 2) & 0x3fc) | ((_v & 0xc) >> 2);
return 0;
}
static inline int start_tsi(struct da9034_touch *touch)
{
return da903x_set_bits(touch->da9034_dev,
DA9034_AUTO_CTRL2, DA9034_AUTO_TSI_EN);
}
static inline int stop_tsi(struct da9034_touch *touch)
{
return da903x_clr_bits(touch->da9034_dev,
DA9034_AUTO_CTRL2, DA9034_AUTO_TSI_EN);
}
static inline void report_pen_down(struct da9034_touch *touch)
{
int x = touch->last_x;
int y = touch->last_y;
x &= 0xfff;
if (touch->x_inverted)
x = 1024 - x;
y &= 0xfff;
if (touch->y_inverted)
y = 1024 - y;
input_report_abs(touch->input_dev, ABS_X, x);
input_report_abs(touch->input_dev, ABS_Y, y);
input_report_key(touch->input_dev, BTN_TOUCH, 1);
input_sync(touch->input_dev);
}
static inline void report_pen_up(struct da9034_touch *touch)
{
input_report_key(touch->input_dev, BTN_TOUCH, 0);
input_sync(touch->input_dev);
}
static void da9034_event_handler(struct da9034_touch *touch, int event)
{
int err;
switch (touch->state) {
case STATE_IDLE:
if (event != EVENT_PEN_DOWN)
break;
/* Enable auto measurement of the TSI, this will
* automatically disable pen down detection
*/
err = start_tsi(touch);
if (err)
goto err_reset;
touch->state = STATE_BUSY;
break;
case STATE_BUSY:
if (event != EVENT_TSI_READY)
break;
err = read_tsi(touch);
if (err)
goto err_reset;
/* Disable auto measurement of the TSI, so that
* pen down status will be available
*/
err = stop_tsi(touch);
if (err)
goto err_reset;
touch->state = STATE_STOP;
/* FIXME: PEN_{UP/DOWN} events are expected to be
* available by stopping TSI, but this is found not
* always true, delay and simulate such an event
* here is more reliable
*/
mdelay(1);
da9034_event_handler(touch,
is_pen_down(touch) ? EVENT_PEN_DOWN :
EVENT_PEN_UP);
break;
case STATE_STOP:
if (event == EVENT_PEN_DOWN) {
report_pen_down(touch);
schedule_delayed_work(&touch->tsi_work,
msecs_to_jiffies(touch->interval_ms));
touch->state = STATE_WAIT;
}
if (event == EVENT_PEN_UP) {
report_pen_up(touch);
touch->state = STATE_IDLE;
}
break;
case STATE_WAIT:
if (event != EVENT_TIMEDOUT)
break;
if (is_pen_down(touch)) {
start_tsi(touch);
touch->state = STATE_BUSY;
} else {
report_pen_up(touch);
touch->state = STATE_IDLE;
}
break;
}
return;
err_reset:
touch->state = STATE_IDLE;
stop_tsi(touch);
detect_pen_down(touch, 1);
}
static void da9034_tsi_work(struct work_struct *work)
{
struct da9034_touch *touch =
container_of(work, struct da9034_touch, tsi_work.work);
da9034_event_handler(touch, EVENT_TIMEDOUT);
}
static int da9034_touch_notifier(struct notifier_block *nb,
unsigned long event, void *data)
{
struct da9034_touch *touch =
container_of(nb, struct da9034_touch, notifier);
if (event & DA9034_EVENT_TSI_READY)
da9034_event_handler(touch, EVENT_TSI_READY);
if ((event & DA9034_EVENT_PEN_DOWN) && touch->state == STATE_IDLE)
da9034_event_handler(touch, EVENT_PEN_DOWN);
return 0;
}
static int da9034_touch_open(struct input_dev *dev)
{
struct da9034_touch *touch = input_get_drvdata(dev);
int ret;
ret = da903x_register_notifier(touch->da9034_dev, &touch->notifier,
DA9034_EVENT_PEN_DOWN | DA9034_EVENT_TSI_READY);
if (ret)
return -EBUSY;
/* Enable ADC LDO */
ret = da903x_set_bits(touch->da9034_dev,
DA9034_MANUAL_CTRL, DA9034_LDO_ADC_EN);
if (ret)
return ret;
/* TSI_DELAY: 3 slots, TSI_SKIP: 3 slots */
ret = da903x_write(touch->da9034_dev, DA9034_TSI_CTRL1, 0x1b);
if (ret)
return ret;
ret = da903x_write(touch->da9034_dev, DA9034_TSI_CTRL2, 0x00);
if (ret)
return ret;
touch->state = STATE_IDLE;
detect_pen_down(touch, 1);
return 0;
}
static void da9034_touch_close(struct input_dev *dev)
{
struct da9034_touch *touch = input_get_drvdata(dev);
da903x_unregister_notifier(touch->da9034_dev, &touch->notifier,
DA9034_EVENT_PEN_DOWN | DA9034_EVENT_TSI_READY);
cancel_delayed_work_sync(&touch->tsi_work);
touch->state = STATE_IDLE;
stop_tsi(touch);
detect_pen_down(touch, 0);
/* Disable ADC LDO */
da903x_clr_bits(touch->da9034_dev,
DA9034_MANUAL_CTRL, DA9034_LDO_ADC_EN);
}
static int da9034_touch_probe(struct platform_device *pdev)
{
struct da9034_touch_pdata *pdata = dev_get_platdata(&pdev->dev);
struct da9034_touch *touch;
struct input_dev *input_dev;
int error;
touch = devm_kzalloc(&pdev->dev, sizeof(struct da9034_touch),
GFP_KERNEL);
if (!touch) {
dev_err(&pdev->dev, "failed to allocate driver data\n");
return -ENOMEM;
}
touch->da9034_dev = pdev->dev.parent;
if (pdata) {
touch->interval_ms = pdata->interval_ms;
touch->x_inverted = pdata->x_inverted;
touch->y_inverted = pdata->y_inverted;
} else {
/* fallback into default */
touch->interval_ms = 10;
}
INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work);
touch->notifier.notifier_call = da9034_touch_notifier;
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev) {
dev_err(&pdev->dev, "failed to allocate input device\n");
return -ENOMEM;
}
input_dev->name = pdev->name;
input_dev->open = da9034_touch_open;
input_dev->close = da9034_touch_close;
input_dev->dev.parent = &pdev->dev;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(ABS_X, input_dev->absbit);
__set_bit(ABS_Y, input_dev->absbit);
input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
touch->input_dev = input_dev;
input_set_drvdata(input_dev, touch);
error = input_register_device(input_dev);
if (error)
return error;
return 0;
}
static struct platform_driver da9034_touch_driver = {
.driver = {
.name = "da9034-touch",
.owner = THIS_MODULE,
},
.probe = da9034_touch_probe,
};
module_platform_driver(da9034_touch_driver);
MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9034");
MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>, Bin Yang <bin.yang@marvell.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9034-touch");

View file

@ -0,0 +1,349 @@
/*
* TSI driver for Dialog DA9052
*
* Copyright(c) 2012 Dialog Semiconductor Ltd.
*
* Author: David Dajun Chen <dchen@diasemi.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/mfd/da9052/reg.h>
#include <linux/mfd/da9052/da9052.h>
#define TSI_PEN_DOWN_STATUS 0x40
struct da9052_tsi {
struct da9052 *da9052;
struct input_dev *dev;
struct delayed_work ts_pen_work;
struct mutex mutex;
bool stopped;
bool adc_on;
};
static void da9052_ts_adc_toggle(struct da9052_tsi *tsi, bool on)
{
da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 0, on);
tsi->adc_on = on;
}
static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data)
{
struct da9052_tsi *tsi = data;
if (!tsi->stopped) {
/* Mask PEN_DOWN event and unmask TSI_READY event */
da9052_disable_irq_nosync(tsi->da9052, DA9052_IRQ_PENDOWN);
da9052_enable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
da9052_ts_adc_toggle(tsi, true);
schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
}
return IRQ_HANDLED;
}
static void da9052_ts_read(struct da9052_tsi *tsi)
{
struct input_dev *input = tsi->dev;
int ret;
u16 x, y, z;
u8 v;
ret = da9052_reg_read(tsi->da9052, DA9052_TSI_X_MSB_REG);
if (ret < 0)
return;
x = (u16) ret;
ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Y_MSB_REG);
if (ret < 0)
return;
y = (u16) ret;
ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Z_MSB_REG);
if (ret < 0)
return;
z = (u16) ret;
ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
if (ret < 0)
return;
v = (u8) ret;
x = ((x << 2) & 0x3fc) | (v & 0x3);
y = ((y << 2) & 0x3fc) | ((v & 0xc) >> 2);
z = ((z << 2) & 0x3fc) | ((v & 0x30) >> 4);
input_report_key(input, BTN_TOUCH, 1);
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
input_report_abs(input, ABS_PRESSURE, z);
input_sync(input);
}
static irqreturn_t da9052_ts_datardy_irq(int irq, void *data)
{
struct da9052_tsi *tsi = data;
da9052_ts_read(tsi);
return IRQ_HANDLED;
}
static void da9052_ts_pen_work(struct work_struct *work)
{
struct da9052_tsi *tsi = container_of(work, struct da9052_tsi,
ts_pen_work.work);
if (!tsi->stopped) {
int ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
if (ret < 0 || (ret & TSI_PEN_DOWN_STATUS)) {
/* Pen is still DOWN (or read error) */
schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
} else {
struct input_dev *input = tsi->dev;
/* Pen UP */
da9052_ts_adc_toggle(tsi, false);
/* Report Pen UP */
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
/*
* FIXME: Fixes the unhandled irq issue when quick
* pen down and pen up events occurs
*/
ret = da9052_reg_update(tsi->da9052,
DA9052_EVENT_B_REG, 0xC0, 0xC0);
if (ret < 0)
return;
/* Mask TSI_READY event and unmask PEN_DOWN event */
da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
}
}
}
static int da9052_ts_configure_gpio(struct da9052 *da9052)
{
int error;
error = da9052_reg_update(da9052, DA9052_GPIO_2_3_REG, 0x30, 0);
if (error < 0)
return error;
error = da9052_reg_update(da9052, DA9052_GPIO_4_5_REG, 0x33, 0);
if (error < 0)
return error;
error = da9052_reg_update(da9052, DA9052_GPIO_6_7_REG, 0x33, 0);
if (error < 0)
return error;
return 0;
}
static int da9052_configure_tsi(struct da9052_tsi *tsi)
{
int error;
error = da9052_ts_configure_gpio(tsi->da9052);
if (error)
return error;
/* Measure TSI sample every 1ms */
error = da9052_reg_update(tsi->da9052, DA9052_ADC_CONT_REG,
1 << 6, 1 << 6);
if (error < 0)
return error;
/* TSI_DELAY: 3 slots, TSI_SKIP: 0 slots, TSI_MODE: XYZP */
error = da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 0xFC, 0xC0);
if (error < 0)
return error;
/* Supply TSIRef through LD09 */
error = da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x59);
if (error < 0)
return error;
return 0;
}
static int da9052_ts_input_open(struct input_dev *input_dev)
{
struct da9052_tsi *tsi = input_get_drvdata(input_dev);
tsi->stopped = false;
mb();
/* Unmask PEN_DOWN event */
da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
/* Enable Pen Detect Circuit */
return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG,
1 << 1, 1 << 1);
}
static void da9052_ts_input_close(struct input_dev *input_dev)
{
struct da9052_tsi *tsi = input_get_drvdata(input_dev);
tsi->stopped = true;
mb();
da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
cancel_delayed_work_sync(&tsi->ts_pen_work);
if (tsi->adc_on) {
da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
da9052_ts_adc_toggle(tsi, false);
/*
* If ADC was on that means that pendwn IRQ was disabled
* twice and we need to enable it to keep enable/disable
* counter balanced. IRQ is still off though.
*/
da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
}
/* Disable Pen Detect Circuit */
da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
}
static int da9052_ts_probe(struct platform_device *pdev)
{
struct da9052 *da9052;
struct da9052_tsi *tsi;
struct input_dev *input_dev;
int error;
da9052 = dev_get_drvdata(pdev->dev.parent);
if (!da9052)
return -EINVAL;
tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL);
input_dev = input_allocate_device();
if (!tsi || !input_dev) {
error = -ENOMEM;
goto err_free_mem;
}
tsi->da9052 = da9052;
tsi->dev = input_dev;
tsi->stopped = true;
INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work);
input_dev->id.version = 0x0101;
input_dev->id.vendor = 0x15B6;
input_dev->id.product = 0x9052;
input_dev->name = "Dialog DA9052 TouchScreen Driver";
input_dev->dev.parent = &pdev->dev;
input_dev->open = da9052_ts_input_open;
input_dev->close = da9052_ts_input_close;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1023, 0, 0);
input_set_drvdata(input_dev, tsi);
/* Disable Pen Detect Circuit */
da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
/* Disable ADC */
da9052_ts_adc_toggle(tsi, false);
error = da9052_request_irq(tsi->da9052, DA9052_IRQ_PENDOWN,
"pendown-irq", da9052_ts_pendwn_irq, tsi);
if (error) {
dev_err(tsi->da9052->dev,
"Failed to register PENDWN IRQ: %d\n", error);
goto err_free_mem;
}
error = da9052_request_irq(tsi->da9052, DA9052_IRQ_TSIREADY,
"tsiready-irq", da9052_ts_datardy_irq, tsi);
if (error) {
dev_err(tsi->da9052->dev,
"Failed to register TSIRDY IRQ :%d\n", error);
goto err_free_pendwn_irq;
}
/* Mask PEN_DOWN and TSI_READY events */
da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN);
da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY);
error = da9052_configure_tsi(tsi);
if (error)
goto err_free_datardy_irq;
error = input_register_device(tsi->dev);
if (error)
goto err_free_datardy_irq;
platform_set_drvdata(pdev, tsi);
return 0;
err_free_datardy_irq:
da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi);
err_free_pendwn_irq:
da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi);
err_free_mem:
kfree(tsi);
input_free_device(input_dev);
return error;
}
static int da9052_ts_remove(struct platform_device *pdev)
{
struct da9052_tsi *tsi = platform_get_drvdata(pdev);
da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19);
da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi);
da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi);
input_unregister_device(tsi->dev);
kfree(tsi);
return 0;
}
static struct platform_driver da9052_tsi_driver = {
.probe = da9052_ts_probe,
.remove = da9052_ts_remove,
.driver = {
.name = "da9052-tsi",
.owner = THIS_MODULE,
},
};
module_platform_driver(da9052_tsi_driver);
MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9052");
MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9052-tsi");

View file

@ -0,0 +1,190 @@
/*
* Dynapro serial touchscreen driver
*
* Copyright (c) 2009 Tias Guns
* Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and
* Richard Lemon
*
*/
/*
* 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.
*/
/*
* 2009/09/19 Tias Guns <tias@ulyssis.org>
* Copied inexio.c and edited for Dynapro protocol (from retired Xorg module)
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#define DRIVER_DESC "Dynapro serial touchscreen driver"
MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/*
* Definitions & global arrays.
*/
#define DYNAPRO_FORMAT_TOUCH_BIT 0x40
#define DYNAPRO_FORMAT_LENGTH 3
#define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80
#define DYNAPRO_MIN_XC 0
#define DYNAPRO_MAX_XC 0x3ff
#define DYNAPRO_MIN_YC 0
#define DYNAPRO_MAX_YC 0x3ff
#define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4))
#define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7))
#define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0])
/*
* Per-touchscreen data.
*/
struct dynapro {
struct input_dev *dev;
struct serio *serio;
int idx;
unsigned char data[DYNAPRO_FORMAT_LENGTH];
char phys[32];
};
static void dynapro_process_data(struct dynapro *pdynapro)
{
struct input_dev *dev = pdynapro->dev;
if (DYNAPRO_FORMAT_LENGTH == ++pdynapro->idx) {
input_report_abs(dev, ABS_X, DYNAPRO_GET_XC(pdynapro->data));
input_report_abs(dev, ABS_Y, DYNAPRO_GET_YC(pdynapro->data));
input_report_key(dev, BTN_TOUCH,
DYNAPRO_GET_TOUCHED(pdynapro->data));
input_sync(dev);
pdynapro->idx = 0;
}
}
static irqreturn_t dynapro_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct dynapro *pdynapro = serio_get_drvdata(serio);
pdynapro->data[pdynapro->idx] = data;
if (DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro->data[0])
dynapro_process_data(pdynapro);
else
dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
pdynapro->data[0]);
return IRQ_HANDLED;
}
static void dynapro_disconnect(struct serio *serio)
{
struct dynapro *pdynapro = serio_get_drvdata(serio);
input_get_device(pdynapro->dev);
input_unregister_device(pdynapro->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_put_device(pdynapro->dev);
kfree(pdynapro);
}
/*
* dynapro_connect() is the routine that is called when someone adds a
* new serio device that supports dynapro protocol and registers it as
* an input device. This is usually accomplished using inputattach.
*/
static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
{
struct dynapro *pdynapro;
struct input_dev *input_dev;
int err;
pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL);
input_dev = input_allocate_device();
if (!pdynapro || !input_dev) {
err = -ENOMEM;
goto fail1;
}
pdynapro->serio = serio;
pdynapro->dev = input_dev;
snprintf(pdynapro->phys, sizeof(pdynapro->phys),
"%s/input0", serio->phys);
input_dev->name = "Dynapro Serial TouchScreen";
input_dev->phys = pdynapro->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_DYNAPRO;
input_dev->id.product = 0;
input_dev->id.version = 0x0001;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(pdynapro->dev, ABS_X,
DYNAPRO_MIN_XC, DYNAPRO_MAX_XC, 0, 0);
input_set_abs_params(pdynapro->dev, ABS_Y,
DYNAPRO_MIN_YC, DYNAPRO_MAX_YC, 0, 0);
serio_set_drvdata(serio, pdynapro);
err = serio_open(serio, drv);
if (err)
goto fail2;
err = input_register_device(pdynapro->dev);
if (err)
goto fail3;
return 0;
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(pdynapro);
return err;
}
/*
* The serio driver structure.
*/
static struct serio_device_id dynapro_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_DYNAPRO,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, dynapro_serio_ids);
static struct serio_driver dynapro_drv = {
.driver = {
.name = "dynapro",
},
.description = DRIVER_DESC,
.id_table = dynapro_serio_ids,
.interrupt = dynapro_interrupt,
.connect = dynapro_connect,
.disconnect = dynapro_disconnect,
};
module_serio_driver(dynapro_drv);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,329 @@
/*
* Touch Screen driver for EETI's I2C connected touch screen panels
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
*
* See EETI's software guide for the protocol specification:
* http://home.eeti.com.tw/web20/eg/guide.htm
*
* Based on migor_ts.c
* Copyright (c) 2008 Magnus Damm
* Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com>
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This file 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/input/eeti_ts.h>
#include <linux/slab.h>
static bool flip_x;
module_param(flip_x, bool, 0644);
MODULE_PARM_DESC(flip_x, "flip x coordinate");
static bool flip_y;
module_param(flip_y, bool, 0644);
MODULE_PARM_DESC(flip_y, "flip y coordinate");
struct eeti_ts_priv {
struct i2c_client *client;
struct input_dev *input;
struct work_struct work;
struct mutex mutex;
int irq_gpio, irq, irq_active_high;
};
#define EETI_TS_BITDEPTH (11)
#define EETI_MAXVAL ((1 << (EETI_TS_BITDEPTH + 1)) - 1)
#define REPORT_BIT_PRESSED (1 << 0)
#define REPORT_BIT_AD0 (1 << 1)
#define REPORT_BIT_AD1 (1 << 2)
#define REPORT_BIT_HAS_PRESSURE (1 << 6)
#define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH)
static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv)
{
return gpio_get_value(priv->irq_gpio) == priv->irq_active_high;
}
static void eeti_ts_read(struct work_struct *work)
{
char buf[6];
unsigned int x, y, res, pressed, to = 100;
struct eeti_ts_priv *priv =
container_of(work, struct eeti_ts_priv, work);
mutex_lock(&priv->mutex);
while (eeti_ts_irq_active(priv) && --to)
i2c_master_recv(priv->client, buf, sizeof(buf));
if (!to) {
dev_err(&priv->client->dev,
"unable to clear IRQ - line stuck?\n");
goto out;
}
/* drop non-report packets */
if (!(buf[0] & 0x80))
goto out;
pressed = buf[0] & REPORT_BIT_PRESSED;
res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1));
x = buf[2] | (buf[1] << 8);
y = buf[4] | (buf[3] << 8);
/* fix the range to 11 bits */
x >>= res - EETI_TS_BITDEPTH;
y >>= res - EETI_TS_BITDEPTH;
if (flip_x)
x = EETI_MAXVAL - x;
if (flip_y)
y = EETI_MAXVAL - y;
if (buf[0] & REPORT_BIT_HAS_PRESSURE)
input_report_abs(priv->input, ABS_PRESSURE, buf[5]);
input_report_abs(priv->input, ABS_X, x);
input_report_abs(priv->input, ABS_Y, y);
input_report_key(priv->input, BTN_TOUCH, !!pressed);
input_sync(priv->input);
out:
mutex_unlock(&priv->mutex);
}
static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
{
struct eeti_ts_priv *priv = dev_id;
/* postpone I2C transactions as we are atomic */
schedule_work(&priv->work);
return IRQ_HANDLED;
}
static void eeti_ts_start(struct eeti_ts_priv *priv)
{
enable_irq(priv->irq);
/* Read the events once to arm the IRQ */
eeti_ts_read(&priv->work);
}
static void eeti_ts_stop(struct eeti_ts_priv *priv)
{
disable_irq(priv->irq);
cancel_work_sync(&priv->work);
}
static int eeti_ts_open(struct input_dev *dev)
{
struct eeti_ts_priv *priv = input_get_drvdata(dev);
eeti_ts_start(priv);
return 0;
}
static void eeti_ts_close(struct input_dev *dev)
{
struct eeti_ts_priv *priv = input_get_drvdata(dev);
eeti_ts_stop(priv);
}
static int eeti_ts_probe(struct i2c_client *client,
const struct i2c_device_id *idp)
{
struct eeti_ts_platform_data *pdata = dev_get_platdata(&client->dev);
struct eeti_ts_priv *priv;
struct input_dev *input;
unsigned int irq_flags;
int err = -ENOMEM;
/*
* In contrast to what's described in the datasheet, there seems
* to be no way of probing the presence of that device using I2C
* commands. So we need to blindly believe it is there, and wait
* for interrupts to occur.
*/
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&client->dev, "failed to allocate driver data\n");
goto err0;
}
mutex_init(&priv->mutex);
input = input_allocate_device();
if (!input) {
dev_err(&client->dev, "Failed to allocate input device.\n");
goto err1;
}
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0);
input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 0xff, 0, 0);
input->name = client->name;
input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev;
input->open = eeti_ts_open;
input->close = eeti_ts_close;
priv->client = client;
priv->input = input;
priv->irq_gpio = pdata->irq_gpio;
priv->irq = gpio_to_irq(pdata->irq_gpio);
err = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name);
if (err < 0)
goto err1;
priv->irq_active_high = pdata->irq_active_high;
irq_flags = priv->irq_active_high ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
INIT_WORK(&priv->work, eeti_ts_read);
i2c_set_clientdata(client, priv);
input_set_drvdata(input, priv);
err = input_register_device(input);
if (err)
goto err2;
err = request_irq(priv->irq, eeti_ts_isr, irq_flags,
client->name, priv);
if (err) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
goto err3;
}
/*
* Disable the device for now. It will be enabled once the
* input device is opened.
*/
eeti_ts_stop(priv);
device_init_wakeup(&client->dev, 0);
return 0;
err3:
input_unregister_device(input);
input = NULL; /* so we dont try to free it below */
err2:
gpio_free(pdata->irq_gpio);
err1:
input_free_device(input);
kfree(priv);
err0:
return err;
}
static int eeti_ts_remove(struct i2c_client *client)
{
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
free_irq(priv->irq, priv);
/*
* eeti_ts_stop() leaves IRQ disabled. We need to re-enable it
* so that device still works if we reload the driver.
*/
enable_irq(priv->irq);
input_unregister_device(priv->input);
kfree(priv);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int eeti_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
mutex_lock(&input_dev->mutex);
if (input_dev->users)
eeti_ts_stop(priv);
mutex_unlock(&input_dev->mutex);
if (device_may_wakeup(&client->dev))
enable_irq_wake(priv->irq);
return 0;
}
static int eeti_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
if (device_may_wakeup(&client->dev))
disable_irq_wake(priv->irq);
mutex_lock(&input_dev->mutex);
if (input_dev->users)
eeti_ts_start(priv);
mutex_unlock(&input_dev->mutex);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
static const struct i2c_device_id eeti_ts_id[] = {
{ "eeti_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
static struct i2c_driver eeti_ts_driver = {
.driver = {
.name = "eeti_ts",
.pm = &eeti_ts_pm,
},
.probe = eeti_ts_probe,
.remove = eeti_ts_remove,
.id_table = eeti_ts_id,
};
module_i2c_driver(eeti_ts_driver);
MODULE_DESCRIPTION("EETI Touchscreen driver");
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,285 @@
/*
* Driver for EETI eGalax Multiple Touch Controller
*
* Copyright (C) 2011 Freescale Semiconductor, Inc.
*
* based on max11801_ts.c
*
* 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.
*/
/* EETI eGalax serial touch screen controller is a I2C based multiple
* touch screen controller, it supports 5 point multiple touch. */
/* TODO:
- auto idle mode support
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/input/mt.h>
#include <linux/of_gpio.h>
/*
* Mouse Mode: some panel may configure the controller to mouse mode,
* which can only report one point at a given time.
* This driver will ignore events in this mode.
*/
#define REPORT_MODE_MOUSE 0x1
/*
* Vendor Mode: this mode is used to transfer some vendor specific
* messages.
* This driver will ignore events in this mode.
*/
#define REPORT_MODE_VENDOR 0x3
/* Multiple Touch Mode */
#define REPORT_MODE_MTTOUCH 0x4
#define MAX_SUPPORT_POINTS 5
#define EVENT_VALID_OFFSET 7
#define EVENT_VALID_MASK (0x1 << EVENT_VALID_OFFSET)
#define EVENT_ID_OFFSET 2
#define EVENT_ID_MASK (0xf << EVENT_ID_OFFSET)
#define EVENT_IN_RANGE (0x1 << 1)
#define EVENT_DOWN_UP (0X1 << 0)
#define MAX_I2C_DATA_LEN 10
#define EGALAX_MAX_X 32760
#define EGALAX_MAX_Y 32760
#define EGALAX_MAX_TRIES 100
struct egalax_ts {
struct i2c_client *client;
struct input_dev *input_dev;
};
static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id)
{
struct egalax_ts *ts = dev_id;
struct input_dev *input_dev = ts->input_dev;
struct i2c_client *client = ts->client;
u8 buf[MAX_I2C_DATA_LEN];
int id, ret, x, y, z;
int tries = 0;
bool down, valid;
u8 state;
do {
ret = i2c_master_recv(client, buf, MAX_I2C_DATA_LEN);
} while (ret == -EAGAIN && tries++ < EGALAX_MAX_TRIES);
if (ret < 0)
return IRQ_HANDLED;
if (buf[0] != REPORT_MODE_MTTOUCH) {
/* ignore mouse events and vendor events */
return IRQ_HANDLED;
}
state = buf[1];
x = (buf[3] << 8) | buf[2];
y = (buf[5] << 8) | buf[4];
z = (buf[7] << 8) | buf[6];
valid = state & EVENT_VALID_MASK;
id = (state & EVENT_ID_MASK) >> EVENT_ID_OFFSET;
down = state & EVENT_DOWN_UP;
if (!valid || id > MAX_SUPPORT_POINTS) {
dev_dbg(&client->dev, "point invalid\n");
return IRQ_HANDLED;
}
input_mt_slot(input_dev, id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, down);
dev_dbg(&client->dev, "%s id:%d x:%d y:%d z:%d",
down ? "down" : "up", id, x, y, z);
if (down) {
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
input_report_abs(input_dev, ABS_MT_PRESSURE, z);
}
input_mt_report_pointer_emulation(input_dev, true);
input_sync(input_dev);
return IRQ_HANDLED;
}
/* wake up controller by an falling edge of interrupt gpio. */
static int egalax_wake_up_device(struct i2c_client *client)
{
struct device_node *np = client->dev.of_node;
int gpio;
int ret;
if (!np)
return -ENODEV;
gpio = of_get_named_gpio(np, "wakeup-gpios", 0);
if (!gpio_is_valid(gpio))
return -ENODEV;
ret = gpio_request(gpio, "egalax_irq");
if (ret < 0) {
dev_err(&client->dev,
"request gpio failed, cannot wake up controller: %d\n",
ret);
return ret;
}
/* wake up controller via an falling edge on IRQ gpio. */
gpio_direction_output(gpio, 0);
gpio_set_value(gpio, 1);
/* controller should be waken up, return irq. */
gpio_direction_input(gpio);
gpio_free(gpio);
return 0;
}
static int egalax_firmware_version(struct i2c_client *client)
{
static const u8 cmd[MAX_I2C_DATA_LEN] = { 0x03, 0x03, 0xa, 0x01, 0x41 };
int ret;
ret = i2c_master_send(client, cmd, MAX_I2C_DATA_LEN);
if (ret < 0)
return ret;
return 0;
}
static int egalax_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct egalax_ts *ts;
struct input_dev *input_dev;
int error;
ts = devm_kzalloc(&client->dev, sizeof(struct egalax_ts), GFP_KERNEL);
if (!ts) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
ts->client = client;
ts->input_dev = input_dev;
/* controller may be in sleep, wake it up. */
error = egalax_wake_up_device(client);
if (error) {
dev_err(&client->dev, "Failed to wake up the controller\n");
return error;
}
error = egalax_firmware_version(client);
if (error < 0) {
dev_err(&client->dev, "Failed to read firmware version\n");
return error;
}
input_dev->name = "EETI eGalax Touch Screen";
input_dev->id.bustype = BUS_I2C;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, 0, EGALAX_MAX_X, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, EGALAX_MAX_Y, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_POSITION_Y, 0, EGALAX_MAX_Y, 0, 0);
input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0);
input_set_drvdata(input_dev, ts);
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
egalax_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"egalax_ts", ts);
if (error < 0) {
dev_err(&client->dev, "Failed to register interrupt\n");
return error;
}
error = input_register_device(ts->input_dev);
if (error)
return error;
i2c_set_clientdata(client, ts);
return 0;
}
static const struct i2c_device_id egalax_ts_id[] = {
{ "egalax_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, egalax_ts_id);
#ifdef CONFIG_PM_SLEEP
static int egalax_ts_suspend(struct device *dev)
{
static const u8 suspend_cmd[MAX_I2C_DATA_LEN] = {
0x3, 0x6, 0xa, 0x3, 0x36, 0x3f, 0x2, 0, 0, 0
};
struct i2c_client *client = to_i2c_client(dev);
int ret;
ret = i2c_master_send(client, suspend_cmd, MAX_I2C_DATA_LEN);
return ret > 0 ? 0 : ret;
}
static int egalax_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
return egalax_wake_up_device(client);
}
#endif
static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
static const struct of_device_id egalax_ts_dt_ids[] = {
{ .compatible = "eeti,egalax_ts" },
{ /* sentinel */ }
};
static struct i2c_driver egalax_ts_driver = {
.driver = {
.name = "egalax_ts",
.owner = THIS_MODULE,
.pm = &egalax_ts_pm_ops,
.of_match_table = egalax_ts_dt_ids,
},
.id_table = egalax_ts_id,
.probe = egalax_ts_probe,
};
module_i2c_driver(egalax_ts_driver);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("Touchscreen driver for EETI eGalax touch controller");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,407 @@
/*
* Elo serial touchscreen driver
*
* Copyright (c) 2004 Vojtech Pavlik
*/
/*
* 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.
*/
/*
* This driver can handle serial Elo touchscreens using either the Elo standard
* 'E271-2210' 10-byte protocol, Elo legacy 'E281A-4002' 6-byte protocol, Elo
* legacy 'E271-140' 4-byte protocol and Elo legacy 'E261-280' 3-byte protocol.
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/ctype.h>
#define DRIVER_DESC "Elo serial touchscreen driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/*
* Definitions & global arrays.
*/
#define ELO_MAX_LENGTH 10
#define ELO10_PACKET_LEN 8
#define ELO10_TOUCH 0x03
#define ELO10_PRESSURE 0x80
#define ELO10_LEAD_BYTE 'U'
#define ELO10_ID_CMD 'i'
#define ELO10_TOUCH_PACKET 'T'
#define ELO10_ACK_PACKET 'A'
#define ELI10_ID_PACKET 'I'
/*
* Per-touchscreen data.
*/
struct elo {
struct input_dev *dev;
struct serio *serio;
struct mutex cmd_mutex;
struct completion cmd_done;
int id;
int idx;
unsigned char expected_packet;
unsigned char csum;
unsigned char data[ELO_MAX_LENGTH];
unsigned char response[ELO10_PACKET_LEN];
char phys[32];
};
static void elo_process_data_10(struct elo *elo, unsigned char data)
{
struct input_dev *dev = elo->dev;
elo->data[elo->idx] = data;
switch (elo->idx++) {
case 0:
elo->csum = 0xaa;
if (data != ELO10_LEAD_BYTE) {
dev_dbg(&elo->serio->dev,
"unsynchronized data: 0x%02x\n", data);
elo->idx = 0;
}
break;
case 9:
elo->idx = 0;
if (data != elo->csum) {
dev_dbg(&elo->serio->dev,
"bad checksum: 0x%02x, expected 0x%02x\n",
data, elo->csum);
break;
}
if (elo->data[1] != elo->expected_packet) {
if (elo->data[1] != ELO10_TOUCH_PACKET)
dev_dbg(&elo->serio->dev,
"unexpected packet: 0x%02x\n",
elo->data[1]);
break;
}
if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
if (elo->data[2] & ELO10_PRESSURE)
input_report_abs(dev, ABS_PRESSURE,
(elo->data[8] << 8) | elo->data[7]);
input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
input_sync(dev);
} else if (elo->data[1] == ELO10_ACK_PACKET) {
if (elo->data[2] == '0')
elo->expected_packet = ELO10_TOUCH_PACKET;
complete(&elo->cmd_done);
} else {
memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
elo->expected_packet = ELO10_ACK_PACKET;
}
break;
}
elo->csum += data;
}
static void elo_process_data_6(struct elo *elo, unsigned char data)
{
struct input_dev *dev = elo->dev;
elo->data[elo->idx] = data;
switch (elo->idx++) {
case 0:
if ((data & 0xc0) != 0xc0)
elo->idx = 0;
break;
case 1:
if ((data & 0xc0) != 0x80)
elo->idx = 0;
break;
case 2:
if ((data & 0xc0) != 0x40)
elo->idx = 0;
break;
case 3:
if (data & 0xc0) {
elo->idx = 0;
break;
}
input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
if (elo->id == 2) {
input_report_key(dev, BTN_TOUCH, 1);
input_sync(dev);
elo->idx = 0;
}
break;
case 4:
if (data) {
input_sync(dev);
elo->idx = 0;
}
break;
case 5:
if ((data & 0xf0) == 0) {
input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
input_report_key(dev, BTN_TOUCH, !!elo->data[5]);
}
input_sync(dev);
elo->idx = 0;
break;
}
}
static void elo_process_data_3(struct elo *elo, unsigned char data)
{
struct input_dev *dev = elo->dev;
elo->data[elo->idx] = data;
switch (elo->idx++) {
case 0:
if ((data & 0x7f) != 0x01)
elo->idx = 0;
break;
case 2:
input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
input_report_abs(dev, ABS_X, elo->data[1]);
input_report_abs(dev, ABS_Y, elo->data[2]);
input_sync(dev);
elo->idx = 0;
break;
}
}
static irqreturn_t elo_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct elo *elo = serio_get_drvdata(serio);
switch (elo->id) {
case 0:
elo_process_data_10(elo, data);
break;
case 1:
case 2:
elo_process_data_6(elo, data);
break;
case 3:
elo_process_data_3(elo, data);
break;
}
return IRQ_HANDLED;
}
static int elo_command_10(struct elo *elo, unsigned char *packet)
{
int rc = -1;
int i;
unsigned char csum = 0xaa + ELO10_LEAD_BYTE;
mutex_lock(&elo->cmd_mutex);
serio_pause_rx(elo->serio);
elo->expected_packet = toupper(packet[0]);
init_completion(&elo->cmd_done);
serio_continue_rx(elo->serio);
if (serio_write(elo->serio, ELO10_LEAD_BYTE))
goto out;
for (i = 0; i < ELO10_PACKET_LEN; i++) {
csum += packet[i];
if (serio_write(elo->serio, packet[i]))
goto out;
}
if (serio_write(elo->serio, csum))
goto out;
wait_for_completion_timeout(&elo->cmd_done, HZ);
if (elo->expected_packet == ELO10_TOUCH_PACKET) {
/* We are back in reporting mode, the command was ACKed */
memcpy(packet, elo->response, ELO10_PACKET_LEN);
rc = 0;
}
out:
mutex_unlock(&elo->cmd_mutex);
return rc;
}
static int elo_setup_10(struct elo *elo)
{
static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" };
struct input_dev *dev = elo->dev;
unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD };
if (elo_command_10(elo, packet))
return -1;
dev->id.version = (packet[5] << 8) | packet[4];
input_set_abs_params(dev, ABS_X, 96, 4000, 0, 0);
input_set_abs_params(dev, ABS_Y, 96, 4000, 0, 0);
if (packet[3] & ELO10_PRESSURE)
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
dev_info(&elo->serio->dev,
"%sTouch touchscreen, fw: %02x.%02x, features: 0x%02x, controller: 0x%02x\n",
elo_types[(packet[1] -'0') & 0x03],
packet[5], packet[4], packet[3], packet[7]);
return 0;
}
/*
* elo_disconnect() is the opposite of elo_connect()
*/
static void elo_disconnect(struct serio *serio)
{
struct elo *elo = serio_get_drvdata(serio);
input_get_device(elo->dev);
input_unregister_device(elo->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_put_device(elo->dev);
kfree(elo);
}
/*
* elo_connect() is the routine that is called when someone adds a
* new serio device that supports Gunze protocol and registers it as
* an input device.
*/
static int elo_connect(struct serio *serio, struct serio_driver *drv)
{
struct elo *elo;
struct input_dev *input_dev;
int err;
elo = kzalloc(sizeof(struct elo), GFP_KERNEL);
input_dev = input_allocate_device();
if (!elo || !input_dev) {
err = -ENOMEM;
goto fail1;
}
elo->serio = serio;
elo->id = serio->id.id;
elo->dev = input_dev;
elo->expected_packet = ELO10_TOUCH_PACKET;
mutex_init(&elo->cmd_mutex);
init_completion(&elo->cmd_done);
snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys);
input_dev->name = "Elo Serial TouchScreen";
input_dev->phys = elo->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_ELO;
input_dev->id.product = elo->id;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
serio_set_drvdata(serio, elo);
err = serio_open(serio, drv);
if (err)
goto fail2;
switch (elo->id) {
case 0: /* 10-byte protocol */
if (elo_setup_10(elo))
goto fail3;
break;
case 1: /* 6-byte protocol */
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0);
case 2: /* 4-byte protocol */
input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
break;
case 3: /* 3-byte protocol */
input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0);
break;
}
err = input_register_device(elo->dev);
if (err)
goto fail3;
return 0;
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(elo);
return err;
}
/*
* The serio driver structure.
*/
static struct serio_device_id elo_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_ELO,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, elo_serio_ids);
static struct serio_driver elo_drv = {
.driver = {
.name = "elo",
},
.description = DRIVER_DESC,
.id_table = elo_serio_ids,
.interrupt = elo_interrupt,
.connect = elo_connect,
.disconnect = elo_disconnect,
};
module_serio_driver(elo_drv);

View file

@ -0,0 +1,177 @@
/*
* Fujitsu serial touchscreen driver
*
* Copyright (c) Dmitry Torokhov <dtor@mail.ru>
*/
/*
* 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/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#define DRIVER_DESC "Fujitsu serial touchscreen driver"
MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
#define FUJITSU_LENGTH 5
/*
* Per-touchscreen data.
*/
struct fujitsu {
struct input_dev *dev;
struct serio *serio;
int idx;
unsigned char data[FUJITSU_LENGTH];
char phys[32];
};
/*
* Decode serial data (5 bytes per packet)
* First byte
* 1 C 0 0 R S S S
* Where C is 1 while in calibration mode (which we don't use)
* R is 1 when no coordinate corection was done.
* S are button state
*/
static irqreturn_t fujitsu_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct fujitsu *fujitsu = serio_get_drvdata(serio);
struct input_dev *dev = fujitsu->dev;
if (fujitsu->idx == 0) {
/* resync skip until start of frame */
if ((data & 0xf0) != 0x80)
return IRQ_HANDLED;
} else {
/* resync skip garbage */
if (data & 0x80) {
fujitsu->idx = 0;
return IRQ_HANDLED;
}
}
fujitsu->data[fujitsu->idx++] = data;
if (fujitsu->idx == FUJITSU_LENGTH) {
input_report_abs(dev, ABS_X,
(fujitsu->data[2] << 7) | fujitsu->data[1]);
input_report_abs(dev, ABS_Y,
(fujitsu->data[4] << 7) | fujitsu->data[3]);
input_report_key(dev, BTN_TOUCH,
(fujitsu->data[0] & 0x03) != 2);
input_sync(dev);
fujitsu->idx = 0;
}
return IRQ_HANDLED;
}
/*
* fujitsu_disconnect() is the opposite of fujitsu_connect()
*/
static void fujitsu_disconnect(struct serio *serio)
{
struct fujitsu *fujitsu = serio_get_drvdata(serio);
input_get_device(fujitsu->dev);
input_unregister_device(fujitsu->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_put_device(fujitsu->dev);
kfree(fujitsu);
}
/*
* fujitsu_connect() is the routine that is called when someone adds a
* new serio device that supports the Fujitsu protocol and registers it
* as input device.
*/
static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
{
struct fujitsu *fujitsu;
struct input_dev *input_dev;
int err;
fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
input_dev = input_allocate_device();
if (!fujitsu || !input_dev) {
err = -ENOMEM;
goto fail1;
}
fujitsu->serio = serio;
fujitsu->dev = input_dev;
snprintf(fujitsu->phys, sizeof(fujitsu->phys),
"%s/input0", serio->phys);
input_dev->name = "Fujitsu Serial Touchscreen";
input_dev->phys = fujitsu->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_FUJITSU;
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
serio_set_drvdata(serio, fujitsu);
err = serio_open(serio, drv);
if (err)
goto fail2;
err = input_register_device(fujitsu->dev);
if (err)
goto fail3;
return 0;
fail3:
serio_close(serio);
fail2:
serio_set_drvdata(serio, NULL);
fail1:
input_free_device(input_dev);
kfree(fujitsu);
return err;
}
/*
* The serio driver structure.
*/
static struct serio_device_id fujitsu_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_FUJITSU,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, fujitsu_serio_ids);
static struct serio_driver fujitsu_drv = {
.driver = {
.name = "fujitsu_ts",
},
.description = DRIVER_DESC,
.id_table = fujitsu_serio_ids,
.interrupt = fujitsu_interrupt,
.connect = fujitsu_connect,
.disconnect = fujitsu_disconnect,
};
module_serio_driver(fujitsu_drv);

View file

@ -0,0 +1,188 @@
/*
* Copyright (c) 2000-2001 Vojtech Pavlik
*/
/*
* Gunze AHL-51S touchscreen driver for Linux
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#define DRIVER_DESC "Gunze AHL-51S touchscreen driver"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/*
* Definitions & global arrays.
*/
#define GUNZE_MAX_LENGTH 10
/*
* Per-touchscreen data.
*/
struct gunze {
struct input_dev *dev;
struct serio *serio;
int idx;
unsigned char data[GUNZE_MAX_LENGTH];
char phys[32];
};
static void gunze_process_packet(struct gunze* gunze)
{
struct input_dev *dev = gunze->dev;
if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' ||
(gunze->data[0] != 'T' && gunze->data[0] != 'R')) {
printk(KERN_WARNING "gunze.c: bad packet: >%.*s<\n", GUNZE_MAX_LENGTH, gunze->data);
return;
}
input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10));
input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10));
input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
input_sync(dev);
}
static irqreturn_t gunze_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct gunze* gunze = serio_get_drvdata(serio);
if (data == '\r') {
gunze_process_packet(gunze);
gunze->idx = 0;
} else {
if (gunze->idx < GUNZE_MAX_LENGTH)
gunze->data[gunze->idx++] = data;
}
return IRQ_HANDLED;
}
/*
* gunze_disconnect() is the opposite of gunze_connect()
*/
static void gunze_disconnect(struct serio *serio)
{
struct gunze *gunze = serio_get_drvdata(serio);
input_get_device(gunze->dev);
input_unregister_device(gunze->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_put_device(gunze->dev);
kfree(gunze);
}
/*
* gunze_connect() is the routine that is called when someone adds a
* new serio device that supports Gunze protocol and registers it as
* an input device.
*/
static int gunze_connect(struct serio *serio, struct serio_driver *drv)
{
struct gunze *gunze;
struct input_dev *input_dev;
int err;
gunze = kzalloc(sizeof(struct gunze), GFP_KERNEL);
input_dev = input_allocate_device();
if (!gunze || !input_dev) {
err = -ENOMEM;
goto fail1;
}
gunze->serio = serio;
gunze->dev = input_dev;
snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
input_dev->name = "Gunze AHL-51S TouchScreen";
input_dev->phys = gunze->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_GUNZE;
input_dev->id.product = 0x0051;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, 24, 1000, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 24, 1000, 0, 0);
serio_set_drvdata(serio, gunze);
err = serio_open(serio, drv);
if (err)
goto fail2;
err = input_register_device(gunze->dev);
if (err)
goto fail3;
return 0;
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(gunze);
return err;
}
/*
* The serio driver structure.
*/
static struct serio_device_id gunze_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_GUNZE,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, gunze_serio_ids);
static struct serio_driver gunze_drv = {
.driver = {
.name = "gunze",
},
.description = DRIVER_DESC,
.id_table = gunze_serio_ids,
.interrupt = gunze_interrupt,
.connect = gunze_connect,
.disconnect = gunze_disconnect,
};
module_serio_driver(gunze_drv);

View file

@ -0,0 +1,189 @@
/*
* Hampshire serial touchscreen driver
*
* Copyright (c) 2010 Adam Bennett
* Based on the dynapro driver (c) Tias Guns
*
*/
/*
* 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.
*/
/*
* 2010/04/08 Adam Bennett <abennett72@gmail.com>
* Copied dynapro.c and edited for Hampshire 4-byte protocol
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#define DRIVER_DESC "Hampshire serial touchscreen driver"
MODULE_AUTHOR("Adam Bennett <abennett72@gmail.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/*
* Definitions & global arrays.
*/
#define HAMPSHIRE_FORMAT_TOUCH_BIT 0x40
#define HAMPSHIRE_FORMAT_LENGTH 4
#define HAMPSHIRE_RESPONSE_BEGIN_BYTE 0x80
#define HAMPSHIRE_MIN_XC 0
#define HAMPSHIRE_MAX_XC 0x1000
#define HAMPSHIRE_MIN_YC 0
#define HAMPSHIRE_MAX_YC 0x1000
#define HAMPSHIRE_GET_XC(data) (((data[3] & 0x0c) >> 2) | (data[1] << 2) | ((data[0] & 0x38) << 6))
#define HAMPSHIRE_GET_YC(data) ((data[3] & 0x03) | (data[2] << 2) | ((data[0] & 0x07) << 9))
#define HAMPSHIRE_GET_TOUCHED(data) (HAMPSHIRE_FORMAT_TOUCH_BIT & data[0])
/*
* Per-touchscreen data.
*/
struct hampshire {
struct input_dev *dev;
struct serio *serio;
int idx;
unsigned char data[HAMPSHIRE_FORMAT_LENGTH];
char phys[32];
};
static void hampshire_process_data(struct hampshire *phampshire)
{
struct input_dev *dev = phampshire->dev;
if (HAMPSHIRE_FORMAT_LENGTH == ++phampshire->idx) {
input_report_abs(dev, ABS_X, HAMPSHIRE_GET_XC(phampshire->data));
input_report_abs(dev, ABS_Y, HAMPSHIRE_GET_YC(phampshire->data));
input_report_key(dev, BTN_TOUCH,
HAMPSHIRE_GET_TOUCHED(phampshire->data));
input_sync(dev);
phampshire->idx = 0;
}
}
static irqreturn_t hampshire_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct hampshire *phampshire = serio_get_drvdata(serio);
phampshire->data[phampshire->idx] = data;
if (HAMPSHIRE_RESPONSE_BEGIN_BYTE & phampshire->data[0])
hampshire_process_data(phampshire);
else
dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
phampshire->data[0]);
return IRQ_HANDLED;
}
static void hampshire_disconnect(struct serio *serio)
{
struct hampshire *phampshire = serio_get_drvdata(serio);
input_get_device(phampshire->dev);
input_unregister_device(phampshire->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_put_device(phampshire->dev);
kfree(phampshire);
}
/*
* hampshire_connect() is the routine that is called when someone adds a
* new serio device that supports hampshire protocol and registers it as
* an input device. This is usually accomplished using inputattach.
*/
static int hampshire_connect(struct serio *serio, struct serio_driver *drv)
{
struct hampshire *phampshire;
struct input_dev *input_dev;
int err;
phampshire = kzalloc(sizeof(struct hampshire), GFP_KERNEL);
input_dev = input_allocate_device();
if (!phampshire || !input_dev) {
err = -ENOMEM;
goto fail1;
}
phampshire->serio = serio;
phampshire->dev = input_dev;
snprintf(phampshire->phys, sizeof(phampshire->phys),
"%s/input0", serio->phys);
input_dev->name = "Hampshire Serial TouchScreen";
input_dev->phys = phampshire->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_HAMPSHIRE;
input_dev->id.product = 0;
input_dev->id.version = 0x0001;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(phampshire->dev, ABS_X,
HAMPSHIRE_MIN_XC, HAMPSHIRE_MAX_XC, 0, 0);
input_set_abs_params(phampshire->dev, ABS_Y,
HAMPSHIRE_MIN_YC, HAMPSHIRE_MAX_YC, 0, 0);
serio_set_drvdata(serio, phampshire);
err = serio_open(serio, drv);
if (err)
goto fail2;
err = input_register_device(phampshire->dev);
if (err)
goto fail3;
return 0;
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(phampshire);
return err;
}
/*
* The serio driver structure.
*/
static struct serio_device_id hampshire_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_HAMPSHIRE,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, hampshire_serio_ids);
static struct serio_driver hampshire_drv = {
.driver = {
.name = "hampshire",
},
.description = DRIVER_DESC,
.id_table = hampshire_serio_ids,
.interrupt = hampshire_interrupt,
.connect = hampshire_connect,
.disconnect = hampshire_disconnect,
};
module_serio_driver(hampshire_drv);

View file

@ -0,0 +1,127 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/adc.h>
#include <mach/hp6xx.h>
#define MODNAME "hp680_ts_input"
#define HP680_TS_ABS_X_MIN 40
#define HP680_TS_ABS_X_MAX 950
#define HP680_TS_ABS_Y_MIN 80
#define HP680_TS_ABS_Y_MAX 910
#define PHDR 0xa400012e
#define SCPDR 0xa4000136
static void do_softint(struct work_struct *work);
static struct input_dev *hp680_ts_dev;
static DECLARE_DELAYED_WORK(work, do_softint);
static void do_softint(struct work_struct *work)
{
int absx = 0, absy = 0;
u8 scpdr;
int touched = 0;
if (__raw_readb(PHDR) & PHDR_TS_PEN_DOWN) {
scpdr = __raw_readb(SCPDR);
scpdr |= SCPDR_TS_SCAN_ENABLE;
scpdr &= ~SCPDR_TS_SCAN_Y;
__raw_writeb(scpdr, SCPDR);
udelay(30);
absy = adc_single(ADC_CHANNEL_TS_Y);
scpdr = __raw_readb(SCPDR);
scpdr |= SCPDR_TS_SCAN_Y;
scpdr &= ~SCPDR_TS_SCAN_X;
__raw_writeb(scpdr, SCPDR);
udelay(30);
absx = adc_single(ADC_CHANNEL_TS_X);
scpdr = __raw_readb(SCPDR);
scpdr |= SCPDR_TS_SCAN_X;
scpdr &= ~SCPDR_TS_SCAN_ENABLE;
__raw_writeb(scpdr, SCPDR);
udelay(100);
touched = __raw_readb(PHDR) & PHDR_TS_PEN_DOWN;
}
if (touched) {
input_report_key(hp680_ts_dev, BTN_TOUCH, 1);
input_report_abs(hp680_ts_dev, ABS_X, absx);
input_report_abs(hp680_ts_dev, ABS_Y, absy);
} else {
input_report_key(hp680_ts_dev, BTN_TOUCH, 0);
}
input_sync(hp680_ts_dev);
enable_irq(HP680_TS_IRQ);
}
static irqreturn_t hp680_ts_interrupt(int irq, void *dev)
{
disable_irq_nosync(irq);
schedule_delayed_work(&work, HZ / 20);
return IRQ_HANDLED;
}
static int __init hp680_ts_init(void)
{
int err;
hp680_ts_dev = input_allocate_device();
if (!hp680_ts_dev)
return -ENOMEM;
hp680_ts_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
hp680_ts_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(hp680_ts_dev, ABS_X,
HP680_TS_ABS_X_MIN, HP680_TS_ABS_X_MAX, 0, 0);
input_set_abs_params(hp680_ts_dev, ABS_Y,
HP680_TS_ABS_Y_MIN, HP680_TS_ABS_Y_MAX, 0, 0);
hp680_ts_dev->name = "HP Jornada touchscreen";
hp680_ts_dev->phys = "hp680_ts/input0";
if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
0, MODNAME, NULL) < 0) {
printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
HP680_TS_IRQ);
err = -EBUSY;
goto fail1;
}
err = input_register_device(hp680_ts_dev);
if (err)
goto fail2;
return 0;
fail2: free_irq(HP680_TS_IRQ, NULL);
cancel_delayed_work_sync(&work);
fail1: input_free_device(hp680_ts_dev);
return err;
}
static void __exit hp680_ts_exit(void)
{
free_irq(HP680_TS_IRQ, NULL);
cancel_delayed_work_sync(&work);
input_unregister_device(hp680_ts_dev);
}
module_init(hp680_ts_init);
module_exit(hp680_ts_exit);
MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,248 @@
/*
* HTC Shift touchscreen driver
*
* Copyright (C) 2008 Pau Oliva Fora <pof@eslack.org>
*
* 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/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/isa.h>
#include <linux/ioport.h>
#include <linux/dmi.h>
MODULE_AUTHOR("Pau Oliva Fora <pau@eslack.org>");
MODULE_DESCRIPTION("HTC Shift touchscreen driver");
MODULE_LICENSE("GPL");
#define HTCPEN_PORT_IRQ_CLEAR 0x068
#define HTCPEN_PORT_INIT 0x06c
#define HTCPEN_PORT_INDEX 0x0250
#define HTCPEN_PORT_DATA 0x0251
#define HTCPEN_IRQ 3
#define DEVICE_ENABLE 0xa2
#define DEVICE_DISABLE 0xa3
#define X_INDEX 3
#define Y_INDEX 5
#define TOUCH_INDEX 0xb
#define LSB_XY_INDEX 0xc
#define X_AXIS_MAX 2040
#define Y_AXIS_MAX 2040
static bool invert_x;
module_param(invert_x, bool, 0644);
MODULE_PARM_DESC(invert_x, "If set, X axis is inverted");
static bool invert_y;
module_param(invert_y, bool, 0644);
MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted");
static irqreturn_t htcpen_interrupt(int irq, void *handle)
{
struct input_dev *htcpen_dev = handle;
unsigned short x, y, xy;
/* 0 = press; 1 = release */
outb_p(TOUCH_INDEX, HTCPEN_PORT_INDEX);
if (inb_p(HTCPEN_PORT_DATA)) {
input_report_key(htcpen_dev, BTN_TOUCH, 0);
} else {
outb_p(X_INDEX, HTCPEN_PORT_INDEX);
x = inb_p(HTCPEN_PORT_DATA);
outb_p(Y_INDEX, HTCPEN_PORT_INDEX);
y = inb_p(HTCPEN_PORT_DATA);
outb_p(LSB_XY_INDEX, HTCPEN_PORT_INDEX);
xy = inb_p(HTCPEN_PORT_DATA);
/* get high resolution value of X and Y using LSB */
x = X_AXIS_MAX - ((x * 8) + ((xy >> 4) & 0xf));
y = (y * 8) + (xy & 0xf);
if (invert_x)
x = X_AXIS_MAX - x;
if (invert_y)
y = Y_AXIS_MAX - y;
if (x != X_AXIS_MAX && x != 0) {
input_report_key(htcpen_dev, BTN_TOUCH, 1);
input_report_abs(htcpen_dev, ABS_X, x);
input_report_abs(htcpen_dev, ABS_Y, y);
}
}
input_sync(htcpen_dev);
inb_p(HTCPEN_PORT_IRQ_CLEAR);
return IRQ_HANDLED;
}
static int htcpen_open(struct input_dev *dev)
{
outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT);
return 0;
}
static void htcpen_close(struct input_dev *dev)
{
outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT);
synchronize_irq(HTCPEN_IRQ);
}
static int htcpen_isa_probe(struct device *dev, unsigned int id)
{
struct input_dev *htcpen_dev;
int err = -EBUSY;
if (!request_region(HTCPEN_PORT_IRQ_CLEAR, 1, "htcpen")) {
printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",
HTCPEN_PORT_IRQ_CLEAR);
goto request_region1_failed;
}
if (!request_region(HTCPEN_PORT_INIT, 1, "htcpen")) {
printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",
HTCPEN_PORT_INIT);
goto request_region2_failed;
}
if (!request_region(HTCPEN_PORT_INDEX, 2, "htcpen")) {
printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",
HTCPEN_PORT_INDEX);
goto request_region3_failed;
}
htcpen_dev = input_allocate_device();
if (!htcpen_dev) {
printk(KERN_ERR "htcpen: can't allocate device\n");
err = -ENOMEM;
goto input_alloc_failed;
}
htcpen_dev->name = "HTC Shift EC TouchScreen";
htcpen_dev->id.bustype = BUS_ISA;
htcpen_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
htcpen_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(htcpen_dev, ABS_X, 0, X_AXIS_MAX, 0, 0);
input_set_abs_params(htcpen_dev, ABS_Y, 0, Y_AXIS_MAX, 0, 0);
htcpen_dev->open = htcpen_open;
htcpen_dev->close = htcpen_close;
err = request_irq(HTCPEN_IRQ, htcpen_interrupt, 0, "htcpen",
htcpen_dev);
if (err) {
printk(KERN_ERR "htcpen: irq busy\n");
goto request_irq_failed;
}
inb_p(HTCPEN_PORT_IRQ_CLEAR);
err = input_register_device(htcpen_dev);
if (err)
goto input_register_failed;
dev_set_drvdata(dev, htcpen_dev);
return 0;
input_register_failed:
free_irq(HTCPEN_IRQ, htcpen_dev);
request_irq_failed:
input_free_device(htcpen_dev);
input_alloc_failed:
release_region(HTCPEN_PORT_INDEX, 2);
request_region3_failed:
release_region(HTCPEN_PORT_INIT, 1);
request_region2_failed:
release_region(HTCPEN_PORT_IRQ_CLEAR, 1);
request_region1_failed:
return err;
}
static int htcpen_isa_remove(struct device *dev, unsigned int id)
{
struct input_dev *htcpen_dev = dev_get_drvdata(dev);
input_unregister_device(htcpen_dev);
free_irq(HTCPEN_IRQ, htcpen_dev);
release_region(HTCPEN_PORT_INDEX, 2);
release_region(HTCPEN_PORT_INIT, 1);
release_region(HTCPEN_PORT_IRQ_CLEAR, 1);
return 0;
}
#ifdef CONFIG_PM
static int htcpen_isa_suspend(struct device *dev, unsigned int n,
pm_message_t state)
{
outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT);
return 0;
}
static int htcpen_isa_resume(struct device *dev, unsigned int n)
{
outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT);
return 0;
}
#endif
static struct isa_driver htcpen_isa_driver = {
.probe = htcpen_isa_probe,
.remove = htcpen_isa_remove,
#ifdef CONFIG_PM
.suspend = htcpen_isa_suspend,
.resume = htcpen_isa_resume,
#endif
.driver = {
.owner = THIS_MODULE,
.name = "htcpen",
}
};
static struct dmi_system_id htcshift_dmi_table[] __initdata = {
{
.ident = "Shift",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "High Tech Computer Corp"),
DMI_MATCH(DMI_PRODUCT_NAME, "Shift"),
},
},
{ }
};
MODULE_DEVICE_TABLE(dmi, htcshift_dmi_table);
static int __init htcpen_isa_init(void)
{
if (!dmi_check_system(htcshift_dmi_table))
return -ENODEV;
return isa_register_driver(&htcpen_isa_driver, 1);
}
static void __exit htcpen_isa_exit(void)
{
isa_unregister_driver(&htcpen_isa_driver);
}
module_init(htcpen_isa_init);
module_exit(htcpen_isa_exit);

View file

@ -0,0 +1,360 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/input/ili210x.h>
#define MAX_TOUCHES 2
#define DEFAULT_POLL_PERIOD 20
/* Touchscreen commands */
#define REG_TOUCHDATA 0x10
#define REG_PANEL_INFO 0x20
#define REG_FIRMWARE_VERSION 0x40
#define REG_CALIBRATE 0xcc
struct finger {
u8 x_low;
u8 x_high;
u8 y_low;
u8 y_high;
} __packed;
struct touchdata {
u8 status;
struct finger finger[MAX_TOUCHES];
} __packed;
struct panel_info {
struct finger finger_max;
u8 xchannel_num;
u8 ychannel_num;
} __packed;
struct firmware_version {
u8 id;
u8 major;
u8 minor;
} __packed;
struct ili210x {
struct i2c_client *client;
struct input_dev *input;
bool (*get_pendown_state)(void);
unsigned int poll_period;
struct delayed_work dwork;
};
static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
size_t len)
{
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = &reg,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = buf,
}
};
if (i2c_transfer(client->adapter, msg, 2) != 2) {
dev_err(&client->dev, "i2c transfer failed\n");
return -EIO;
}
return 0;
}
static void ili210x_report_events(struct input_dev *input,
const struct touchdata *touchdata)
{
int i;
bool touch;
unsigned int x, y;
const struct finger *finger;
for (i = 0; i < MAX_TOUCHES; i++) {
input_mt_slot(input, i);
finger = &touchdata->finger[i];
touch = touchdata->status & (1 << i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
if (touch) {
x = finger->x_low | (finger->x_high << 8);
y = finger->y_low | (finger->y_high << 8);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
}
}
input_mt_report_pointer_emulation(input, false);
input_sync(input);
}
static bool get_pendown_state(const struct ili210x *priv)
{
bool state = false;
if (priv->get_pendown_state)
state = priv->get_pendown_state();
return state;
}
static void ili210x_work(struct work_struct *work)
{
struct ili210x *priv = container_of(work, struct ili210x,
dwork.work);
struct i2c_client *client = priv->client;
struct touchdata touchdata;
int error;
error = ili210x_read_reg(client, REG_TOUCHDATA,
&touchdata, sizeof(touchdata));
if (error) {
dev_err(&client->dev,
"Unable to get touchdata, err = %d\n", error);
return;
}
ili210x_report_events(priv->input, &touchdata);
if ((touchdata.status & 0xf3) || get_pendown_state(priv))
schedule_delayed_work(&priv->dwork,
msecs_to_jiffies(priv->poll_period));
}
static irqreturn_t ili210x_irq(int irq, void *irq_data)
{
struct ili210x *priv = irq_data;
schedule_delayed_work(&priv->dwork, 0);
return IRQ_HANDLED;
}
static ssize_t ili210x_calibrate(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct ili210x *priv = i2c_get_clientdata(client);
unsigned long calibrate;
int rc;
u8 cmd = REG_CALIBRATE;
if (kstrtoul(buf, 10, &calibrate))
return -EINVAL;
if (calibrate > 1)
return -EINVAL;
if (calibrate) {
rc = i2c_master_send(priv->client, &cmd, sizeof(cmd));
if (rc != sizeof(cmd))
return -EIO;
}
return count;
}
static DEVICE_ATTR(calibrate, 0644, NULL, ili210x_calibrate);
static struct attribute *ili210x_attributes[] = {
&dev_attr_calibrate.attr,
NULL,
};
static const struct attribute_group ili210x_attr_group = {
.attrs = ili210x_attributes,
};
static int ili210x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
const struct ili210x_platform_data *pdata = dev_get_platdata(dev);
struct ili210x *priv;
struct input_dev *input;
struct panel_info panel;
struct firmware_version firmware;
int xmax, ymax;
int error;
dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
if (!pdata) {
dev_err(dev, "No platform data!\n");
return -EINVAL;
}
if (client->irq <= 0) {
dev_err(dev, "No IRQ!\n");
return -EINVAL;
}
/* Get firmware version */
error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
&firmware, sizeof(firmware));
if (error) {
dev_err(dev, "Failed to get firmware version, err: %d\n",
error);
return error;
}
/* get panel info */
error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel));
if (error) {
dev_err(dev, "Failed to get panel informations, err: %d\n",
error);
return error;
}
xmax = panel.finger_max.x_low | (panel.finger_max.x_high << 8);
ymax = panel.finger_max.y_low | (panel.finger_max.y_high << 8);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
input = input_allocate_device();
if (!priv || !input) {
error = -ENOMEM;
goto err_free_mem;
}
priv->client = client;
priv->input = input;
priv->get_pendown_state = pdata->get_pendown_state;
priv->poll_period = pdata->poll_period ? : DEFAULT_POLL_PERIOD;
INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
/* Setup input device */
input->name = "ILI210x Touchscreen";
input->id.bustype = BUS_I2C;
input->dev.parent = dev;
__set_bit(EV_SYN, input->evbit);
__set_bit(EV_KEY, input->evbit);
__set_bit(EV_ABS, input->evbit);
__set_bit(BTN_TOUCH, input->keybit);
/* Single touch */
input_set_abs_params(input, ABS_X, 0, xmax, 0, 0);
input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
/* Multi touch */
input_mt_init_slots(input, MAX_TOUCHES, 0);
input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
input_set_drvdata(input, priv);
i2c_set_clientdata(client, priv);
error = request_irq(client->irq, ili210x_irq, pdata->irq_flags,
client->name, priv);
if (error) {
dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
error);
goto err_free_mem;
}
error = sysfs_create_group(&dev->kobj, &ili210x_attr_group);
if (error) {
dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
error);
goto err_free_irq;
}
error = input_register_device(priv->input);
if (error) {
dev_err(dev, "Cannot regiser input device, err: %d\n", error);
goto err_remove_sysfs;
}
device_init_wakeup(&client->dev, 1);
dev_dbg(dev,
"ILI210x initialized (IRQ: %d), firmware version %d.%d.%d",
client->irq, firmware.id, firmware.major, firmware.minor);
return 0;
err_remove_sysfs:
sysfs_remove_group(&dev->kobj, &ili210x_attr_group);
err_free_irq:
free_irq(client->irq, priv);
err_free_mem:
input_free_device(input);
kfree(priv);
return error;
}
static int ili210x_i2c_remove(struct i2c_client *client)
{
struct ili210x *priv = i2c_get_clientdata(client);
sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group);
free_irq(priv->client->irq, priv);
cancel_delayed_work_sync(&priv->dwork);
input_unregister_device(priv->input);
kfree(priv);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int ili210x_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
return 0;
}
static int ili210x_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
ili210x_i2c_suspend, ili210x_i2c_resume);
static const struct i2c_device_id ili210x_i2c_id[] = {
{ "ili210x", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
static struct i2c_driver ili210x_ts_driver = {
.driver = {
.name = "ili210x_i2c",
.owner = THIS_MODULE,
.pm = &ili210x_i2c_pm,
},
.id_table = ili210x_i2c_id,
.probe = ili210x_i2c_probe,
.remove = ili210x_i2c_remove,
};
module_i2c_driver(ili210x_ts_driver);
MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,45 @@
#
# Imagis IST30XXC Touchscreen driver
#
config TOUCHSCREEN_IST30XXC
tristate "IST30XXC I2C Touchscreen"
depends on I2C
help
Say Y here if you have the Imagis IST30XXC I2C touchscreen
connected to your system.
config TOUCHSCREEN_IST3026C
tristate "IST3026C I2C Touchscreen"
depends on I2C
help
Say Y here if you have the Imagis IST3026C I2C touchscreen
connected to your system.
config TOUCHSCREEN_IST3032C
tristate "IST3032C I2C Touchscreen"
depends on I2C
help
Say Y here if you have the Imagis IST3032C I2C touchscreen
connected to your system.
config TOUCHSCREEN_IST3038C
tristate "IST3038C I2C Touchscreen"
depends on I2C
help
Say Y here if you have the Imagis IST3038C I2C touchscreen
connected to your system.
config TOUCHSCREEN_IST3044C
tristate "IST3044C I2C Touchscreen"
depends on I2C
help
Say Y here if you have the Imagis IST3044C I2C touchscreen
connected to your system.
config TOUCHSCREEN_IST3048C
tristate "IST3048C I2C Touchscreen"
depends on I2C
help
Say Y here if you have the Imagis IST3048C I2C touchscreen
connected to your system.

View file

@ -0,0 +1,12 @@
#
# Makefile for the Imagis touch driver
#
# Each configuration option enables a list of files.
obj-$(CONFIG_TOUCHSCREEN_IST30XXC) += ist30xxc.o ist30xxc_misc.o ist30xxc_sys.o ist30xxc_update.o ist30xxc_tracking.o ist30xxc_sec.o ist30xxc_cmcs.o
obj-$(CONFIG_TOUCHSCREEN_IST3026C) += ist30xxc.o ist30xxc_misc.o ist30xxc_sys.o ist30xxc_update.o ist30xxc_tracking.o ist30xxc_sec.o ist30xxc_cmcs.o
obj-$(CONFIG_TOUCHSCREEN_IST3032C) += ist30xxc.o ist30xxc_misc.o ist30xxc_sys.o ist30xxc_update.o ist30xxc_tracking.o ist30xxc_sec.o ist30xxc_cmcs.o
obj-$(CONFIG_TOUCHSCREEN_IST3038C) += ist30xxc.o ist30xxc_misc.o ist30xxc_sys.o ist30xxc_update.o ist30xxc_tracking.o ist30xxc_sec.o ist30xxc_cmcs.o
obj-$(CONFIG_TOUCHSCREEN_IST3044C) += ist30xxc.o ist30xxc_misc.o ist30xxc_sys.o ist30xxc_update.o ist30xxc_tracking.o ist30xxc_sec.o ist30xxc_cmcs.o
obj-$(CONFIG_TOUCHSCREEN_IST3048C) += ist30xxc.o ist30xxc_misc.o ist30xxc_sys.o ist30xxc_update.o ist30xxc_tracking.o ist30xxc_sec.o ist30xxc_cmcs.o

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,654 @@
/*
* Copyright (C) 2010, Imagis Technology Co. Ltd. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __IST30XXC_H__
#define __IST30XXC_H__
#ifdef USE_TSP_TA_CALLBACKS
#include <linux/input/tsp_ta_callback.h>
#endif
#if defined(CONFIG_VBUS_NOTIFIER) || defined(CONFIG_MUIC_NOTIFIER)
#include <linux/muic/muic.h>
#include <linux/muic/muic_notifier.h>
#include <linux/vbus_notifier.h>
#endif
#ifdef CONFIG_INPUT_BOOSTER
#include <linux/input/input_booster.h>
#endif
#define USE_OPEN_CLOSE
/*
* Support F/W ver : IST30xxC v1.0.0.0
* Support IC : IST3026C, IST3032C
* Release : 2015.01.05 by Hoony
*/
#define IMAGIS_DD_VERSION ("2.0.0.0")
#define IMAGIS_IST3026C (1) /* 3026C */
#define IMAGIS_IST3032C (2) /* 3032C */
#define IMAGIS_IST3038C (3) /* 3038C */
#define IMAGIS_IST3044C (4) /* 3044C */
#define IMAGIS_IST3048C (5) /* 3048C */
#if defined(CONFIG_TOUCHSCREEN_IST3026C)
#define IMAGIS_TSP_IC IMAGIS_IST3026C
#elif defined(CONFIG_TOUCHSCREEN_IST3032C)
#define IMAGIS_TSP_IC IMAGIS_IST3032C
#elif defined(CONFIG_TOUCHSCREEN_IST3038C)
#define IMAGIS_TSP_IC IMAGIS_IST3038C
#endif
/* SEC defined [*/
#define FIRMWARE_PATH_LENGTH 64
#define FIRMWARE_PATH "tsp_imagis/"
/* SEC defined ] */
#define TSP_CHIP_VENDOR ("IMAGIS")
#define IMAGIS_PROTOCOL_A (0xA)
#define IMAGIS_PROTOCOL_B (0xB)
#define IMAGIS_PROTOCOL_TYPE IMAGIS_PROTOCOL_B
#define IST30XXC_DEFAULT_CHIP_ID (0x300C)
#define IST3048C_DEFAULT_CHIP_ID (0x3048)
#if (IMAGIS_TSP_IC == IMAGIS_IST3026C)
#define TSP_CHIP_NAME ("IST3026C")
#define IST30XX_CHIP_ID (0x026C)
#define IST30XX_NODE_TOTAL_NUM (16 * 16)
#elif (IMAGIS_TSP_IC == IMAGIS_IST3032C)
#define TSP_CHIP_NAME ("IST3032C")
#define IST30XX_CHIP_ID (0x032C)
#define IST30XX_NODE_TOTAL_NUM (16 * 16)
#elif (IMAGIS_TSP_IC == IMAGIS_IST3038C)
#define TSP_CHIP_NAME ("IST3038C")
#define IST30XX_CHIP_ID (0x038C)
#define IST30XX_NODE_TOTAL_NUM (24 * 24)
#elif (IMAGIS_TSP_IC == IMAGIS_IST3044C)
#define TSP_CHIP_NAME ("IST3044C")
#define IST30XX_CHIP_ID (0x044C)
#define IST30XX_NODE_TOTAL_NUM (24 * 24)
#elif (IMAGIS_TSP_IC == IMAGIS_IST3048C)
#define TSP_CHIP_NAME ("IST3048C")
#define IST30XX_CHIP_ID (0x048C)
#define IST30XX_NODE_TOTAL_NUM (24 * 24)
#else
#define TSP_CHIP_NAME ("IST30XXC")
#define IST30XX_CHIP_ID (0x300C)
#define IST30XX_NODE_TOTAL_NUM (24 * 24)
#endif
/* IST30XX FUNCTION ENABLE & DISABLE */
#define IST30XX_INTERNAL_BIN (1)
#define IST30XX_CHECK_CALIB (0)
#if IST30XX_INTERNAL_BIN
#if defined(CONFIG_TOUCHSCREEN_IST3026C) //novel
#define IST30XX_MULTIPLE_TSP (1)
#endif
#define IST30XX_UPDATE_BY_WORKQUEUE (0)
#define IST30XX_UPDATE_DELAY (3 * HZ)
#endif
#define IST30XX_EVENT_MODE (1)
#if IST30XX_EVENT_MODE
#define IST30XX_NOISE_MODE (1)
#define IST30XX_TRACKING_MODE (1)
#define IST30XX_ALGORITHM_MODE (1)
#else
#define IST30XX_NOISE_MODE (0) /* fixed */
#define IST30XX_TRACKING_MODE (0) /* fixed */
#define IST30XX_ALGORITHM_MODE (0) /* fixed */
#endif
#define IST30XX_TA_RESET (1)
#if defined(CONFIG_TOUCHSCREEN_IST3026C) || defined(CONFIG_TOUCHSCREEN_IST3038C)
#define IST30XX_USE_KEY (0)
#else
#define IST30XX_USE_KEY (1)
#endif
#define IST30XX_DEBUG (1)
#define IST30XX_CMCS_TEST (1)
#define IST30XX_GESTURE (0)
#define IST30XX_STATUS_DEBUG (0)
#define SEC_FACTORY_MODE (1)
/* IST30XX FUNCTION ENABLE & DISABLE */
#define IST30XX_ADDR_LEN (4)
#define IST30XX_DATA_LEN (4)
#define IST30XX_MAX_MT_FINGERS (10)
#define IST30XX_MAX_KEYS (5)
#define IST30XX_MAX_X (480) /* LCD Resolution */
#define IST30XX_MAX_Y (800) /* LCD Resolution */
#define IST30XX_MAX_W (15)
#define IST30XX_EXCEPT_MASK (0xFFFFFF00)
#define IST30XX_EXCEPT_VALUE (0xE11CE900)
#define IST30XX_MAX_EXCEPT_SIZE (2)
#define IST30XX_JIG_TOUCH (0xC0)
#define IST30XX_ENABLE (1)
#define IST30XX_DISABLE (0)
/* retry count */
#define IST30XX_MAX_RETRY_CNT (3)
/* Local */
#define TSP_LOCAL_EU (0)
#define TSP_LOCAL_EEU (1)
#define TSP_LOCAL_TD (11)
#define TSP_LOCAL_CMCC (12)
#define TSP_LOCAL_CU (13)
#define TSP_LOCAL_SPRD (14)
#define TSP_LOCAL_CTC (15)
#define TSP_LOCAL_INDIA (21)
#define TSP_LOCAL_SWASIA (22)
#define TSP_LOCAL_NA (31)
#define TSP_LOCAL_LA (32)
#define TSP_LOCAL_CODE TSP_LOCAL_EU
/* Factory Test for Reliability Test Group */
enum ist30xx_reliability_commands {
TEST_RAW_ALL_DATA = 0,
TEST_CM_ALL_DATA,
TEST_CS_ALL_DATA,
TEST_SLOPE_ALL_DATA,
};
/* Debug message */
#define DEV_ERR (1)
#define DEV_WARN (2)
#define DEV_INFO (3)
#define DEV_NOTI (4)
#define DEV_DEBUG (5)
#define DEV_VERB (6)
#define IST30XX_DEBUG_TAG "[ TSP ]"
#define IST30XX_DEBUG_LEVEL DEV_NOTI
#ifdef CONFIG_SEC_DEBUG_TSP_LOG
#include <linux/sec_debug.h>
#endif
#ifdef CONFIG_SEC_DEBUG_TSP_LOG
#define tsp_err(fmt, ...) \
({ \
if (IST30XX_DEBUG_LEVEL<DEV_ERR) \
tsp_printk(DEV_ERR, fmt, ## __VA_ARGS__); \
else{ \
tsp_printk(DEV_ERR, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
})
#define tsp_warn(fmt, ...) \
({ \
if (IST30XX_DEBUG_LEVEL<DEV_WARN) \
tsp_printk(DEV_WARN, fmt, ## __VA_ARGS__); \
else{ \
tsp_printk(DEV_WARN, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
})
#define tsp_info(fmt, ...) \
({ \
if (IST30XX_DEBUG_LEVEL<DEV_INFO) \
tsp_printk(DEV_INFO, fmt, ## __VA_ARGS__); \
else{ \
tsp_printk(DEV_INFO, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
})
#define tsp_noti(fmt, ...) \
({ \
if (IST30XX_DEBUG_LEVEL<DEV_NOTI) \
tsp_printk(DEV_NOTI, fmt, ## __VA_ARGS__); \
else{ \
tsp_printk(DEV_NOTI, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
})
#define tsp_debug(fmt, ...) \
({ \
if (IST30XX_DEBUG_LEVEL<DEV_DEBUG) \
tsp_printk(DEV_DEBUG, fmt, ## __VA_ARGS__); \
else{ \
tsp_printk(DEV_DEBUG, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
})
#define tsp_verb(fmt, ...) \
({ \
if (IST30XX_DEBUG_LEVEL<DEV_VERB) \
tsp_printk(DEV_VERB, fmt, ## __VA_ARGS__); \
else{ \
tsp_printk(DEV_VERB, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
})
#else
#define tsp_err(fmt, ...) tsp_printk(DEV_ERR, fmt, ## __VA_ARGS__)
#define tsp_warn(fmt, ...) tsp_printk(DEV_WARN, fmt, ## __VA_ARGS__)
#define tsp_info(fmt, ...) tsp_printk(DEV_INFO, fmt, ## __VA_ARGS__)
#define tsp_noti(fmt, ...) tsp_printk(DEV_NOTI, fmt, ## __VA_ARGS__)
#define tsp_debug(fmt, ...) tsp_printk(DEV_DEBUG, fmt, ## __VA_ARGS__)
#define tsp_verb(fmt, ...) tsp_printk(DEV_VERB, fmt, ## __VA_ARGS__)
#endif
/* i2c setting */
/* I2C Device info */
#define IST30XX_DEV_NAME "IST30XX"
#define IST30XX_DEV_ID (0xA0 >> 1)
/* I2C Mode */
#define I2C_BURST_MODE (1)
#define I2C_MONOPOLY_MODE (0)
/* I2C transfer msg number */
#define WRITE_CMD_MSG_LEN (1)
#define READ_CMD_MSG_LEN (2)
/* I2C address/Data length */
#define IST30XX_ADDR_LEN (4) /* bytes */
#define IST30XX_DATA_LEN (4) /* bytes */
/* I2C transaction size */
#define I2C_MAX_WRITE_SIZE (0x0100) /* bytes */
#define I2C_MAX_READ_SIZE (0x0080) /* bytes */
/* I2C access mode */
#define IST30XX_DIRECT_ACCESS (1 << 31)
#define IST30XX_BURST_ACCESS (1 << 27)
#define IST30XX_HIB_ACCESS (0x800B << 16)
#define IST30XX_DA_ADDR(n) (n | IST30XX_DIRECT_ACCESS)
#define IST30XX_BA_ADDR(n) (n | IST30XX_BURST_ACCESS)
#define IST30XX_HA_ADDR(n) (n | IST30XX_HIB_ACCESS)
/* register */
/* Info register */
#define IST30XX_REG_CHIPID IST30XX_DA_ADDR(0x40001000)
#define IST30XX_REG_TSPTYPE IST30XX_DA_ADDR(0x40002010)
/* SEC defined [ */
#define IST30XX_REG_XY_RES IST30XX_DA_ADDR(0x40)
#define IST30XX_REG_XY_SWAP IST30XX_DA_ADDR(0x5C)
/* SEC defined ] */
/* HIB register */
#define IST30XX_HIB_BASE (0x30000100)
#define IST30XX_HIB_TOUCH_STATUS IST30XX_HA_ADDR(IST30XX_HIB_BASE | 0x00)
#define IST30XX_HIB_INTR_MSG IST30XX_HA_ADDR(IST30XX_HIB_BASE | 0x04)
#define IST30XX_HIB_COORD IST30XX_HA_ADDR(IST30XX_HIB_BASE | 0x08)
#define IST30XX_HIB_CMD IST30XX_HA_ADDR(IST30XX_HIB_BASE | 0x3C)
#define IST30XX_HIB_RW_STATUS IST30XX_HA_ADDR(IST30XX_HIB_BASE | 0x40)
/* interrupt macro */
#define IST30XX_INTR_STATUS (0x00000C00)
#define CHECK_INTR_STATUS(n) (((n & IST30XX_INTR_STATUS) == IST30XX_INTR_STATUS) ? 1 : 0)
#define PARSE_FINGER_CNT(n) ((n >> 12) & 0xF)
#define PARSE_KEY_CNT(n) ((n >> 21) & 0x7)
/* Finger status: [9:0] */
#define PARSE_FINGER_STATUS(n) (n & 0x3FF)
/* Key status: [20:16] */
#define PARSE_KEY_STATUS(n) ((n >> 16) & 0x1F)
#define PRESSED_FINGER(s, id) ((s & (1 << (id - 1))) ? true : false)
#define PRESSED_KEY(s, id) ((s & (1 << (16 + id - 1))) ? true : false)
#define IST30XX_MAX_CMD_SIZE (0x20)
#define IST30XX_CMD_ADDR(n) (n * 4)
#define IST30XX_CMD_VALUE(n) (n / 4)
enum ist30xx_read_commands {
eHCOM_GET_CHIP_ID = IST30XX_CMD_ADDR(0x00),
eHCOM_GET_VER_MAIN = IST30XX_CMD_ADDR(0x01),
eHCOM_GET_VER_FW = IST30XX_CMD_ADDR(0x02),
eHCOM_GET_VER_CORE = IST30XX_CMD_ADDR(0x03),
eHCOM_GET_VER_TEST = IST30XX_CMD_ADDR(0x04),
eHCOM_GET_CRC32 = IST30XX_CMD_ADDR(0x05),
eHCOM_GET_CRC32_ALL = IST30XX_CMD_ADDR(0x06),
eHCOM_GET_CAL_RESULT = IST30XX_CMD_ADDR(0x07),
eHCOM_GET_TSP_VENDOR = IST30XX_CMD_ADDR(0x08),
eHCOM_GET_LCD_INFO = IST30XX_CMD_ADDR(0x10),
eHCOM_GET_TSP_INFO = IST30XX_CMD_ADDR(0x11),
eHCOM_GET_KEY_INFO_0 = IST30XX_CMD_ADDR(0x12),
eHCOM_GET_KEY_INFO_1 = IST30XX_CMD_ADDR(0x13),
eHCOM_GET_KEY_INFO_2 = IST30XX_CMD_ADDR(0x14),
eHCOM_GET_SCR_INFO = IST30XX_CMD_ADDR(0x15),
eHCOM_GET_GTX_INFO = IST30XX_CMD_ADDR(0x16),
eHCOM_GET_SWAP_INFO = IST30XX_CMD_ADDR(0x17),
eHCOM_GET_FINGER_INFO = IST30XX_CMD_ADDR(0x18),
eHCOM_GET_BASELINE = IST30XX_CMD_ADDR(0x19),
eHCOM_GET_TOUCH_TH = IST30XX_CMD_ADDR(0x1A),
eHCOM_GET_ZVALUE_BASE = IST30XX_CMD_ADDR(0x1C),
eHCOM_GET_CDC_BASE = IST30XX_CMD_ADDR(0x1D),
eHCOM_GET_ALGO_BASE = IST30XX_CMD_ADDR(0x1E),
eHCOM_GET_COM_CHECKSUM = IST30XX_CMD_ADDR(0x1F),
};
enum ist30xx_write_commands {
eHCOM_FW_START = 0x01,
eHCOM_FW_HOLD = 0x02,
eHCOM_CP_CORRECT_EN = 0x10,
eHCOM_WDT_EN = 0x11,
eHCOM_GESTURE_EN = 0x12,
eHCOM_SCALE_EN = 0x13,
eHCOM_NEW_POSITION_DIS = 0x14,
eHCOM_SLEEP_MODE_EN = 0x15,
eHCOM_SET_TIME_ACTIVE = 0x20,
eHCOM_SET_TIME_IDLE = 0x21,
eHCOM_SET_MODE_SPECIAL = 0x22,
eHCOM_SET_LOCAL_MODEL = 0x23,
eHCOM_RUN_RAMCODE = 0x30,
eHCOM_RUN_CAL_AUTO = 0x31,
eHCOM_RUN_CAL_PARAM = 0x32,
eHCOM_SET_JIG_MODE = 0x80,
eHCOM_SET_JIG_SENSITI = 0x81,
eHCOM_DEFAULT = 0xFF,
};
typedef union {
struct {
u32 y:12;
u32 x:12;
u32 area:4;
u32 id:4;
} bit_field;
u32 full_field;
} finger_info;
struct ist30xx_status {
int power;
int update;
int update_result;
int calib;
int calib_msg;
u32 cmcs;
bool event_mode;
bool noise_mode;
};
struct ist30xx_version {
u32 main_ver;
u32 fw_ver;
u32 core_ver;
u32 test_ver;
};
struct ist30xx_fw {
struct ist30xx_version prev;
struct ist30xx_version cur;
struct ist30xx_version bin;
u32 index;
u32 size;
u32 chksum;
u32 buf_size;
u8 *buf;
};
#define IST30XX_TAG_MAGIC "ISTV2TAG"
struct ist30xx_tags {
char magic1[8];
u32 rom_base;
u32 ram_base;
u32 reserved0;
u32 reserved1;
u32 fw_addr;
u32 fw_size;
u32 cfg_addr;
u32 cfg_size;
u32 sensor_addr;
u32 sensor_size;
u32 cp_addr;
u32 cp_size;
u32 flag_addr;
u32 flag_size;
u32 reserved2;
u32 reserved3;
u32 zvalue_base;
u32 algo_base;
u32 raw_base;
u32 filter_base;
u32 reserved4;
u32 reserved5;
u32 chksum;
u32 chksum_all;
u32 reserved6;
u32 reserved7;
u8 day;
u8 month;
u16 year;
u8 hour;
u8 min;
u8 sec;
u8 reserved8;
char magic2[8];
};
struct ist30xx_platform_data {
int max_x;
int max_y;
int max_w;
int irq_flag;
int avdd_volt;
struct regulator *avdd_regulator;
};
struct CH_NUM {
u8 tx;
u8 rx;
};
struct GTX_INFO {
u8 num;
u8 ch_num[4];
};
struct TSP_NODE_BUF {
u16 raw[IST30XX_NODE_TOTAL_NUM];
u16 base[IST30XX_NODE_TOTAL_NUM];
u16 filter[IST30XX_NODE_TOTAL_NUM];
u16 min_raw;
u16 max_raw;
u16 min_base;
u16 max_base;
u16 len;
};
struct TSP_DIRECTION {
bool swap_xy;
bool flip_x;
bool flip_y;
};
typedef struct _TSP_INFO {
struct CH_NUM ch_num;
struct CH_NUM screen;
struct GTX_INFO gtx;
struct TSP_DIRECTION dir;
struct TSP_NODE_BUF node;
int height;
int width;
int finger_num;
u16 baseline;
} TSP_INFO;
typedef struct _TKEY_INFO {
int key_num;
bool enable;
struct CH_NUM ch_num[IST30XX_MAX_KEYS];
u16 baseline;
} TKEY_INFO;
#if SEC_FACTORY_MODE
#include "ist30xxc_sec.h"
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
struct ist30xx_dt_data {
int irq_gpio;
int touch_en_gpio;
const char *tsp_vdd_name;
struct regulator *tsp_power;
int fw_bin;
int octa_hw;
const char *ic_version;
const char *project_name;
char fw_path[FIRMWARE_PATH_LENGTH];
char cmcs_path[FIRMWARE_PATH_LENGTH];
const char *regulator_avdd;
};
struct ist30xx_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct ist30xx_dt_data *dt_data;
struct ist30xx_platform_data *pdata;
TSP_INFO tsp_info;
TKEY_INFO tkey_info;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif
struct ist30xx_status status;
struct ist30xx_fw fw;
struct ist30xx_tags tags;
struct pinctrl *pinctrl;
#if SEC_FACTORY_MODE
struct sec_factory sec;
#endif
u32 chip_id;
u32 tsp_type;
u32 max_fingers;
u32 max_keys;
u32 t_status;
finger_info fingers[IST30XX_MAX_MT_FINGERS];
u32 lx;
u32 ly;
volatile bool irq_working;
u32 irq_enabled;
bool initialized;
u32 noise_mode;
u32 debug_mode;
u32 jig_mode;
u32 z_values[IST30XX_MAX_MT_FINGERS];
int report_rate;
int idle_rate;
#if IST30XX_GESTURE
bool suspend;
bool gesture;
#endif
int touch_pressed_num;
#ifdef CONFIG_INPUT_BOOSTER
struct input_booster *tsp_booster;
#endif
int scan_count;
int scan_retry;
int max_scan_retry;
int irq_err_cnt;
int max_irq_err_cnt;
/* SEC defined [*/
u16 max_x;
u16 max_y;
bool track_enable;
/* SEC defined ]*/
struct delayed_work work_reset_check;
struct delayed_work work_noise_protect;
struct delayed_work work_debug_algorithm;
#if IST30XX_INTERNAL_BIN
#if IST30XX_UPDATE_BY_WORKQUEUE
struct delayed_work work_fw_update;
#endif
#endif
bool touch_stopped;
#ifdef USE_TSP_TA_CALLBACKS
struct tsp_callbacks callbacks;
#endif
#ifdef CONFIG_MUIC_NOTIFIER
struct notifier_block muic_nb;
#endif
#ifdef CONFIG_VBUS_NOTIFIER
struct notifier_block vbus_nb;
#endif
};
extern struct mutex ist30xx_mutex;
extern int ist30xx_dbg_level;
extern unsigned int system_rev;
void tsp_printk(int level, const char *fmt, ...);
int ist30xx_intr_wait(struct ist30xx_data *data, long ms);
void ist30xx_enable_irq(struct ist30xx_data *data);
void ist30xx_disable_irq(struct ist30xx_data *data);
void ist30xx_set_ta_mode(bool charging);
void ist30xx_set_edge_mode(int mode);
void ist30xx_set_cover_mode(int mode);
void ist30xx_start(struct ist30xx_data *data);
int ist30xx_get_ver_info(struct ist30xx_data *data);
int ist30xx_read_reg(struct i2c_client *client, u32 reg, u32 *buf);
int ist30xx_read_cmd(struct ist30xx_data *data, u32 cmd, u32 *buf);
int ist30xx_write_cmd(struct i2c_client *client, u32 cmd, u32 val);
int ist30xx_read_buf(struct i2c_client *client, u32 cmd, u32 *buf, u16 len);
int ist30xx_write_buf(struct i2c_client *client, u32 cmd, u32 *buf, u16 len);
int ist30xx_burst_read(struct i2c_client *client, u32 addr,
u32 *buf32, u16 len, bool bit_en);
int ist30xx_burst_write(struct i2c_client *client, u32 addr,
u32 *buf32, u16 len);
int ist30xx_cmd_start_scan(struct ist30xx_data *data);
int ist30xx_cmd_calibrate(struct i2c_client *client);
int ist30xx_cmd_check_calib(struct i2c_client *client);
int ist30xx_cmd_update(struct i2c_client *client, int cmd);
int ist30xx_cmd_hold(struct ist30xx_data *data, int enable);
int ist30xx_power_on(struct ist30xx_data *data, bool download);
int ist30xx_power_off(struct ist30xx_data *data);
int ist30xx_reset(struct ist30xx_data *data, bool download);
int ist30xx_internal_suspend(struct ist30xx_data *data);
int ist30xx_internal_resume(struct ist30xx_data *data);
int ist30xx_init_system(struct ist30xx_data *data);
extern struct class *ist30xx_class;
#if SEC_FACTORY_MODE
extern struct class *sec_class;
extern int sec_touch_sysfs(struct ist30xx_data *data);
extern int sec_fac_cmd_init(struct ist30xx_data *data);
extern void sec_fac_cmd_remove(struct ist30xx_data *data);
extern void sec_touch_sysfs_remove(struct ist30xx_data *data);
#endif
#endif /* __IST30XXC_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,159 @@
/*
* Copyright (C) 2010, Imagis Technology Co. Ltd. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __IST30XXC_CMCS_H__
#define __IST30XXC_CMCS_H__
#define INTERNAL_CMCS_BIN (1)
#define CMCS_PARSING_DEBUG (0)
#define CMCS_RAMCODE_READ (0)
#define CMCS_FLAG_CM (1)
#define CMCS_FLAG_CM_SPEC (1 << 1)
#define CMCS_FLAG_CM_SLOPE0 (1 << 2)
#define CMCS_FLAG_CM_SLOPE1 (1 << 3)
#define CMCS_FLAG_CS (1 << 4)
#define CMCS_READY (0)
#define CMCS_NOT_READY (-1)
#define IST30XX_CMCS_MSG_VALID (0x8FAB0FAB)
#define IST30XX_CMCS_TIMEOUT (10000) // unit : msec
#define IST30XX_CMCS_CM ("CM")
#define IST30XX_CMCS_CS ("CS")
// CMCS addr
#define IST30XX_CMCS_CHECKSUM IST30XX_DA_ADDR(0x300B0100)
#define IST30XX_CMCS_CS_CHECKSUM IST30XX_DA_ADDR(0x300B0108)
#define IST30XX_CMCS_PATTERN IST30XX_DA_ADDR(0x300B0104)
#define ENABLE_CM_MODE(n) (n & 1)
#define ENABLE_CS_MODE(n) ((n >> 1) & 1)
#define IST30XX_CMCS_NAME "ist30xxc.cms"
#define IST30XX_CMCS_MAGIC "CMCS2TAG"
struct CMCS_SPEC_NODE {
u32 node_cnt;
u16 *buf_min;
u16 *buf_max;
};
struct CMCS_SPEC_TOTAL {
s16 screen_min;
s16 screen_max;
s16 gtx_min;
s16 gtx_max;
s16 key_min;
s16 key_max;
};
struct CMCS_ITEM_INFO {
char name[8];
u32 addr;
u32 size;
char data_type[2];
char spec_type[2];
};
typedef struct _CMCS_ITEM {
u32 cnt;
struct CMCS_ITEM_INFO *item;
} CMCS_ITEM;
struct CMCS_CMD_INFO {
u32 addr;
u32 value;
};
typedef struct _CMCS_CMD {
u32 cnt;
struct CMCS_CMD_INFO *cmd;
} CMCS_CMD;
union CMCS_SPEC_ITEM {
struct CMCS_SPEC_NODE spec_node;
struct CMCS_SPEC_TOTAL spec_total;
};
struct CMCS_SPEC_SLOPE {
char name[8];
s16 x_min;
s16 x_max;
s16 gtx_x_min;
s16 gtx_x_max;
s16 y_min;
s16 y_max;
s16 gtx_y_min;
s16 gtx_y_max;
s16 key_min;
s16 key_max;
};
struct CMCS_REG_INFO {
char name[8];
u32 addr;
u32 size;
};
typedef struct _CMCS_PARAM {
u32 cmcs_size_addr;
u32 cmcs_size;
u32 cm_sensor1_addr;
u32 cm_sensor1_size;
u32 cm_sensor2_addr;
u32 cm_sensor2_size;
u32 cm_sensor3_addr;
u32 cm_sensor3_size;
u32 cs_sensor1_addr;
u32 cs_sensor1_size;
u32 cs_sensor2_addr;
u32 cs_sensor2_size;
u32 cs_sensor3_addr;
u32 cs_sensor3_size;
u32 cmcs_chksum;
u32 cm_sensor_chksum;
u32 cs_sensor_chksum;
} CMCS_PARAM;
typedef struct _CMCS_BIN_INFO {
char magic1[8];
CMCS_ITEM items;
CMCS_CMD cmds;
struct CMCS_SPEC_SLOPE spec_slope;
struct CMCS_SPEC_TOTAL spec_cr;
CMCS_PARAM param;
union CMCS_SPEC_ITEM *spec_item;
u8 *buf_cmcs;
u32 * buf_sensor;
char magic2[8];
} CMCS_BIN_INFO;
typedef struct _CMCS_BUF {
s16 cm[IST30XX_NODE_TOTAL_NUM];
s16 spec_min[IST30XX_NODE_TOTAL_NUM];
s16 spec_max[IST30XX_NODE_TOTAL_NUM];
s16 slope0[IST30XX_NODE_TOTAL_NUM];
s16 slope1[IST30XX_NODE_TOTAL_NUM];
s16 cs[IST30XX_NODE_TOTAL_NUM];
} CMCS_BUF;
int check_tsp_type(struct ist30xx_data *data, int tx, int rx);
int ist30xx_get_cmcs_info(const u8 *buf, const u32 size);
int ist30xx_cmcs_test(struct ist30xx_data *data, const u8 *buf, int size);
int ist30xx_init_cmcs_sysfs(struct ist30xx_data *data);
#endif // __IST30XXC_CMCS_H__

View file

@ -0,0 +1,615 @@
#ifndef __IST30XX_CMCS_BIN_H__
#define __IST30XX_CMCS_BIN_H__
/* ist30xx cmcs binary: model( ) */
static unsigned char ist30xx_cmcs[] = {
0x43, 0x4d, 0x43, 0x53, 0x32, 0x54, 0x41, 0x47, 0x02, 0x00, 0x00, 0x00, 0x43, 0x4d, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x1e, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x4e, 0x00, 0x4e, 0x00,
0x43, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
0x4e, 0x00, 0x54, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x11, 0x00, 0x00, 0xac, 0x0d, 0xac, 0x0d,
0x28, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x43, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00,
0x38, 0xff, 0xc8, 0x00, 0xbc, 0x02, 0x14, 0x05, 0xbc, 0x02, 0x32, 0x05, 0x30, 0x02, 0x10, 0x04,
0x20, 0x11, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x08, 0x70, 0x00, 0x40, 0x00, 0x03, 0x00, 0x00,
0x00, 0x40, 0x00, 0x30, 0x00, 0x09, 0x00, 0x00, 0xc4, 0x52, 0x00, 0x30, 0x50, 0x01, 0x00, 0x00,
0x30, 0x11, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x30, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
0x30, 0x1d, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x3d, 0x32, 0x09, 0xd2, 0x60, 0x28, 0xd6, 0x1f,
0x61, 0x18, 0xd4, 0x69, 0x08, 0x01, 0x00, 0x00, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xf0, 0x0a, 0xe4, 0x0c, 0xf0, 0x0a, 0xe4, 0x0c,
0xc4, 0x09, 0xe4, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x10, 0xa8, 0x10, 0x0c, 0x80, 0x5c, 0x06,
0x2b, 0x2b, 0x00, 0x00, 0xf2, 0xfe, 0x00, 0x00, 0x08, 0x70, 0x00, 0x40, 0x38, 0x67, 0x08, 0x70,
0xb9, 0x67, 0x08, 0x70, 0xe1, 0xf0, 0x00, 0x00, 0x08, 0x60, 0x00, 0x40, 0x38, 0x76, 0x08, 0x70,
0xd6, 0x72, 0x82, 0xfd, 0xe1, 0xf0, 0x00, 0x00, 0x08, 0x60, 0x00, 0x40, 0x38, 0x76, 0x70, 0x70,
0x64, 0x71, 0xb9, 0x76, 0x70, 0x70, 0xe1, 0xf0, 0x08, 0x60, 0x00, 0x40, 0x38, 0x76, 0x70, 0x70,
0x64, 0x72, 0xb9, 0x76, 0x70, 0x70, 0xe1, 0xf0, 0x67, 0x31, 0x14, 0x71, 0x34, 0x31, 0xc6, 0x37,
0x82, 0x04, 0xb1, 0x02, 0x24, 0x24, 0xf2, 0xfb, 0xe1, 0xf0, 0x00, 0x00, 0x77, 0x41, 0x14, 0x71,
0x34, 0x41, 0xc6, 0x47, 0x82, 0x04, 0xb1, 0x32, 0x24, 0x24, 0xf2, 0xfb, 0xe1, 0xf0, 0x00, 0x00,
0xf7, 0x40, 0x04, 0x70, 0xc6, 0x74, 0x82, 0x07, 0x2f, 0x67, 0x07, 0x00, 0x26, 0x62, 0xa1, 0x36,
0x24, 0x71, 0xf2, 0xf9, 0xe1, 0xf0, 0x00, 0x00, 0x04, 0x70, 0xc6, 0x74, 0x82, 0x06, 0x2f, 0x67,
0x02, 0x00, 0x91, 0x36, 0x24, 0x71, 0xf2, 0xfa, 0xe1, 0xf0, 0x00, 0x00, 0x34, 0x14, 0xb1, 0xf1,
0x77, 0x41, 0x04, 0x70, 0x14, 0x61, 0x34, 0x41, 0xc6, 0x46, 0x82, 0x09, 0x2f, 0x57, 0x03, 0x00,
0x30, 0xf5, 0x2f, 0x57, 0x02, 0x00, 0xb1, 0xf5, 0x24, 0x74, 0xf2, 0xf6, 0x30, 0xf1, 0x24, 0x14,
0xe1, 0xf0, 0x00, 0x00, 0x34, 0x14, 0x0c, 0x70, 0x4a, 0x01, 0xb1, 0x71, 0x30, 0x71, 0x14, 0x61,
0xc4, 0x70, 0x26, 0x67, 0xb1, 0x61, 0x92, 0xfb, 0x24, 0x14, 0xe1, 0xf0, 0x34, 0x1c, 0x26, 0x22,
0xc9, 0xe1, 0x04, 0x00, 0x06, 0xe2, 0xb1, 0x01, 0x57, 0xe1, 0xb1, 0x01, 0x26, 0xe2, 0x30, 0x71,
0xc6, 0x7e, 0xb2, 0x07, 0x8b, 0x06, 0x00, 0x00, 0x30, 0x71, 0x24, 0x71, 0xb1, 0x71, 0xf2, 0xf8,
0x48, 0xe1, 0x04, 0x00, 0x24, 0x1c, 0xe1, 0xf0, 0x08, 0x60, 0x00, 0x30, 0x38, 0x76, 0x28, 0x00,
0xd4, 0x74, 0x92, 0xfd, 0xe1, 0xf0, 0x00, 0x00, 0x77, 0x31, 0x04, 0x70, 0x14, 0x61, 0x34, 0x31,
0xc6, 0x36, 0x82, 0x05, 0x30, 0x52, 0x24, 0x24, 0x26, 0x75, 0xf2, 0xfa, 0x06, 0x27, 0xe1, 0xf0,
0x04, 0x6c, 0xa9, 0x60, 0xa6, 0x0f, 0x0c, 0x60, 0x16, 0x00, 0xa9, 0x60, 0xa4, 0x0f, 0x04, 0x6a,
0xa9, 0x60, 0xa2, 0x0f, 0x0c, 0x60, 0x13, 0x00, 0xa9, 0x60, 0xa0, 0x0f, 0x0c, 0x50, 0xee, 0x00,
0x06, 0x76, 0x0c, 0x70, 0x5c, 0x0f, 0xb9, 0x50, 0x5c, 0x0f, 0x0c, 0x60, 0xef, 0x00, 0xb9, 0x67,
0x04, 0x00, 0x0c, 0x60, 0xf3, 0x0c, 0xb9, 0x67, 0x08, 0x00, 0xb9, 0x67, 0x0c, 0x00, 0xb9, 0x67,
0x10, 0x00, 0xe1, 0xf0, 0x3c, 0x10, 0x10, 0x00, 0xd1, 0xc1, 0x06, 0xd3, 0x78, 0x30, 0xa6, 0x0f,
0x06, 0xe2, 0x06, 0xc4, 0xcb, 0x31, 0x00, 0x00, 0x78, 0x60, 0xa2, 0x0f, 0x2f, 0x7d, 0x02, 0x00,
0xc6, 0xd6, 0xb1, 0x7c, 0xa2, 0x12, 0x06, 0x56, 0x0c, 0x50, 0x5c, 0x0f, 0x38, 0x55, 0x04, 0x00,
0x04, 0x20, 0xc6, 0x75, 0x92, 0x03, 0x28, 0x20, 0x7a, 0x0f, 0x38, 0x60, 0x5c, 0x0f, 0xc6, 0x76,
0x92, 0x10, 0x28, 0x20, 0x7a, 0x0f, 0xf2, 0x0d, 0x78, 0x70, 0xa0, 0x0f, 0xc6, 0xe7, 0xb2, 0x04,
0x28, 0x20, 0x78, 0x0f, 0xf2, 0x06, 0x3c, 0xe0, 0x14, 0x00, 0xc4, 0xe1, 0xc2, 0xfa, 0x04, 0x20,
0x50, 0xc1, 0x2c, 0x10, 0x10, 0x00, 0xe1, 0xf0, 0x08, 0x70, 0x0f, 0xc0, 0x2c, 0x70, 0xff, 0xff,
0x08, 0x60, 0x00, 0x40, 0xb9, 0x76, 0x3c, 0x71, 0x08, 0x70, 0x00, 0x30, 0x2c, 0x70, 0x00, 0x40,
0x57, 0x21, 0x2f, 0x57, 0x02, 0x00, 0x30, 0x75, 0xc4, 0x40, 0x0c, 0x60, 0xff, 0x03, 0x56, 0x67,
0x77, 0x75, 0x5c, 0x70, 0xff, 0x03, 0x82, 0x09, 0xc4, 0x30, 0x82, 0x04, 0x26, 0x64, 0x26, 0x74,
0xf2, 0x11, 0x36, 0x74, 0x36, 0x64, 0xf2, 0x0e, 0xc4, 0x30, 0x82, 0x07, 0xc6, 0x76, 0x02, 0x03,
0x24, 0x61, 0xf2, 0x0d, 0x24, 0x71, 0xf2, 0x06, 0xc6, 0x76, 0x02, 0x03, 0x34, 0x71, 0xf2, 0x02,
0x34, 0x61, 0xc4, 0x60, 0x02, 0x06, 0xcc, 0x60, 0xff, 0x03, 0x12, 0x06, 0x04, 0x20, 0xf2, 0x07,
0x14, 0x21, 0x04, 0x61, 0xf2, 0x04, 0x14, 0x21, 0x0c, 0x60, 0xff, 0x03, 0xc4, 0x70, 0x02, 0x08,
0xcc, 0x70, 0xff, 0x03, 0x02, 0x07, 0x14, 0x21, 0x0c, 0x70, 0xff, 0x03, 0xf2, 0x03, 0x14, 0x21,
0x04, 0x71, 0x57, 0x75, 0x66, 0x76, 0xb1, 0x75, 0x08, 0x70, 0x00, 0x40, 0xb9, 0x07, 0x3c, 0x71,
0xe1, 0xf0, 0x00, 0x00, 0x3c, 0x10, 0x24, 0x00, 0xd9, 0xc1, 0x14, 0x00, 0x06, 0xe2, 0x78, 0x20,
0xa0, 0x0f, 0xd9, 0x81, 0x04, 0x00, 0x78, 0x30, 0xa2, 0x0f, 0x24, 0x22, 0xcb, 0x31, 0x00, 0x00,
0x04, 0x92, 0x26, 0x92, 0x23, 0x3e, 0x0c, 0x20, 0xdc, 0x0a, 0x0c, 0x40, 0x10, 0x02, 0xeb, 0x03,
0x00, 0x00, 0x06, 0x2d, 0x0c, 0x20, 0x9c, 0x08, 0x04, 0x30, 0x0c, 0x40, 0x08, 0x01, 0xab, 0x04,
0x00, 0x00, 0x06, 0x2e, 0x0c, 0x20, 0x5c, 0x06, 0x04, 0x31, 0x0c, 0x40, 0x08, 0x01, 0xab, 0x04,
0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x04, 0x61, 0x08, 0x70, 0x00, 0x40, 0x08, 0xa0, 0x00, 0x30,
0xb9, 0x67, 0x00, 0x70, 0x0c, 0xb0, 0x82, 0x00, 0x2c, 0xa0, 0x00, 0x49, 0x04, 0x21, 0x04, 0xd0,
0x2b, 0x01, 0x00, 0x00, 0x06, 0xed, 0x78, 0x70, 0xa4, 0x0f, 0xc6, 0xd7, 0x32, 0x48, 0x04, 0xc0,
0x78, 0x70, 0xa6, 0x0f, 0xc6, 0xc7, 0x32, 0x41, 0x06, 0x2d, 0x06, 0x3c, 0x06, 0x41, 0x0b, 0x0c,
0x00, 0x00, 0x86, 0x62, 0x82, 0x38, 0x30, 0x21, 0x06, 0x72, 0x57, 0x71, 0x26, 0x7a, 0x30, 0x77,
0x0c, 0x80, 0x9c, 0x08, 0x5c, 0x70, 0xff, 0x0f, 0x3f, 0x66, 0x07, 0x00, 0x2f, 0x72, 0x08, 0x00,
0x90, 0xf7, 0x82, 0x04, 0xcc, 0x60, 0x46, 0x00, 0x02, 0x25, 0x0c, 0x30, 0x5c, 0x06, 0x2f, 0x72,
0x03, 0x00, 0x10, 0x57, 0xc4, 0x51, 0x0c, 0x40, 0xdc, 0x0a, 0x2f, 0x52, 0x02, 0x00, 0x92, 0x05,
0xc4, 0x60, 0x22, 0x0e, 0x91, 0x07, 0xf2, 0x0c, 0xc4, 0x60, 0x12, 0x0a, 0x04, 0x61, 0x91, 0x67,
0x2f, 0x75, 0x04, 0x00, 0xa0, 0x77, 0x92, 0x04, 0x26, 0x82, 0x24, 0xf1, 0x91, 0xf8, 0x26, 0x54,
0x20, 0x45, 0x26, 0x32, 0x10, 0x33, 0xf7, 0x40, 0xa1, 0x45, 0x2b, 0x0f, 0x00, 0x00, 0xc4, 0x20,
0x32, 0x02, 0x24, 0xe1, 0x24, 0xc1, 0xf2, 0xbd, 0x24, 0xd1, 0xf2, 0xb6, 0xc6, 0xe9, 0xb2, 0x0b,
0xb4, 0xb1, 0x82, 0x09, 0xab, 0x00, 0x00, 0x00, 0x04, 0x61, 0x08, 0x70, 0x00, 0x40, 0xb9, 0x67,
0x00, 0x70, 0xf2, 0xa5, 0x58, 0xc1, 0x14, 0x00, 0x58, 0x81, 0x04, 0x00, 0x2c, 0x10, 0x24, 0x00,
0xe1, 0xf0, 0x00, 0x00, 0x34, 0x18, 0x08, 0x70, 0x0f, 0xc0, 0xc1, 0xe1, 0x2c, 0x70, 0xff, 0xff,
0x08, 0xe0, 0x00, 0x40, 0xb9, 0x7e, 0x3c, 0x71, 0x28, 0x70, 0x76, 0x0f, 0x08, 0x20, 0x00, 0x30,
0x06, 0x37, 0x57, 0x35, 0x2c, 0x20, 0x00, 0x40, 0x66, 0x37, 0x0c, 0x40, 0x00, 0x09, 0x4b, 0x03,
0x00, 0x00, 0xb9, 0x0e, 0x3c, 0x71, 0x0c, 0x20, 0x00, 0x02, 0x0b, 0x14, 0x00, 0x00, 0x40, 0xe1,
0x24, 0x18, 0xe1, 0xf0, 0x3c, 0x10, 0x20, 0x00, 0xd9, 0xc1, 0x10, 0x00, 0xd1, 0x81, 0x08, 0xe0,
0x00, 0x30, 0x38, 0x6e, 0x6c, 0x53, 0x0c, 0x70, 0x74, 0x0f, 0xb9, 0x67, 0x08, 0x00, 0x38, 0x6e,
0x70, 0x53, 0x0c, 0xc0, 0x6c, 0x53, 0xb9, 0x67, 0x0c, 0x00, 0x38, 0x6e, 0x74, 0x53, 0x06, 0xd2,
0xb9, 0x67, 0x10, 0x00, 0x38, 0x6e, 0x78, 0x53, 0x26, 0xce, 0xb9, 0x67, 0x14, 0x00, 0x38, 0x6e,
0x7c, 0x53, 0xb9, 0x67, 0x18, 0x00, 0x38, 0x6e, 0x80, 0x53, 0xb9, 0x67, 0x1c, 0x00, 0x38, 0x6e,
0x84, 0x53, 0xb9, 0x67, 0x20, 0x00, 0x38, 0x6e, 0x88, 0x53, 0xb9, 0x67, 0x24, 0x00, 0xb9, 0x0e,
0x6c, 0x53, 0xb9, 0x0e, 0x7c, 0x53, 0xb9, 0x0e, 0x70, 0x53, 0xb9, 0x0e, 0x80, 0x53, 0xb9, 0x0e,
0x74, 0x53, 0xb9, 0x0e, 0x84, 0x53, 0xb9, 0x0e, 0x78, 0x53, 0xb9, 0x0e, 0x88, 0x53, 0x8b, 0x1d,
0x00, 0x00, 0x06, 0x6d, 0x06, 0x7c, 0x2c, 0xe0, 0x7c, 0x53, 0x38, 0x56, 0x08, 0x00, 0xb1, 0x57,
0x90, 0x5d, 0x92, 0x05, 0x38, 0x56, 0x18, 0x00, 0xb9, 0x57, 0x10, 0x00, 0x24, 0x74, 0xc6, 0x7e,
0x24, 0x64, 0x92, 0xf4, 0xab, 0x01, 0x00, 0x00, 0x04, 0xcb, 0x2b, 0x02, 0x00, 0x00, 0x04, 0xb1,
0x08, 0xe0, 0x00, 0x40, 0xb4, 0xc1, 0x82, 0x09, 0xab, 0x00, 0x00, 0x00, 0x04, 0x21, 0xb9, 0xbe,
0x00, 0x70, 0x2b, 0x01, 0x00, 0x00, 0xf2, 0xf7, 0x08, 0xb0, 0x00, 0x30, 0x2c, 0xb0, 0x00, 0x49,
0x78, 0x70, 0xa4, 0x0f, 0xc6, 0xc7, 0x32, 0x27, 0x04, 0xe0, 0x78, 0x30, 0xa6, 0x0f, 0xc6, 0xe3,
0x32, 0x20, 0x06, 0x2c, 0xcb, 0x31, 0x00, 0x00, 0x90, 0x5d, 0x38, 0x6d, 0x28, 0x00, 0x26, 0x2e,
0x2f, 0x72, 0x02, 0x00, 0x26, 0x67, 0x57, 0x21, 0x92, 0x0d, 0x26, 0x2b, 0x30, 0x72, 0x28, 0x4d,
0x04, 0x00, 0x5c, 0x70, 0xff, 0x0f, 0x3f, 0x77, 0x04, 0x00, 0xc4, 0x70, 0x32, 0x07, 0x06, 0x75,
0xf2, 0x05, 0x26, 0x2b, 0x30, 0x72, 0x5c, 0x70, 0xff, 0x0f, 0xa1, 0x76, 0x24, 0xe1, 0xf2, 0xde,
0x24, 0xc1, 0xf2, 0xd7, 0x58, 0xc1, 0x10, 0x00, 0x50, 0x81, 0x2c, 0x10, 0x20, 0x00, 0xe1, 0xf0,
0x08, 0x20, 0x00, 0x40, 0x34, 0x18, 0x2c, 0x20, 0x08, 0x70, 0x0c, 0x30, 0x38, 0x11, 0x0c, 0x40,
0xf8, 0x02, 0xc1, 0xe1, 0x4b, 0x05, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x40, 0x08, 0xe0, 0x00, 0x30,
0x26, 0x2e, 0x0c, 0x30, 0x30, 0x14, 0x0c, 0x40, 0x00, 0x09, 0x4b, 0x05, 0x00, 0x00, 0x0c, 0x20,
0xc4, 0x52, 0x26, 0x2e, 0x0c, 0x30, 0x30, 0x1d, 0x0c, 0x40, 0x50, 0x01, 0x4b, 0x05, 0x00, 0x00,
0x40, 0xe1, 0x24, 0x18, 0xe1, 0xf0, 0x00, 0x00, 0x3c, 0x10, 0x20, 0x00, 0xd1, 0x81, 0x08, 0x70,
0x00, 0x30, 0xd9, 0xc1, 0x10, 0x00, 0x2c, 0x70, 0x00, 0x01, 0x06, 0x29, 0x0c, 0x20, 0x80, 0x1e,
0x0c, 0x30, 0x80, 0x04, 0xb9, 0x70, 0x70, 0x0f, 0xab, 0x02, 0x00, 0x00, 0x06, 0x2a, 0x0c, 0x20,
0x00, 0x23, 0x0c, 0x30, 0x80, 0x04, 0xab, 0x02, 0x00, 0x00, 0xab, 0x08, 0x00, 0x00, 0x38, 0x30,
0x20, 0x11, 0x38, 0xe0, 0x70, 0x0f, 0x04, 0x20, 0x06, 0xc7, 0x0c, 0xc0, 0x20, 0x11, 0x2b, 0x09,
0x00, 0x00, 0xb1, 0x2e, 0x0c, 0x20, 0x30, 0x11, 0x0c, 0x30, 0x80, 0x1e, 0x36, 0x32, 0x2b, 0x09,
0x00, 0x00, 0xb9, 0x2e, 0x08, 0x00, 0x38, 0x7c, 0x04, 0x00, 0x06, 0xeb, 0x0c, 0xe0, 0x74, 0x0f,
0xa9, 0x7e, 0x04, 0x00, 0x77, 0x78, 0xa9, 0x7e, 0x06, 0x00, 0xeb, 0x09, 0x00, 0x00, 0x38, 0x7c,
0x08, 0x00, 0x99, 0x00, 0x74, 0x0f, 0x06, 0x2e, 0x0c, 0x90, 0x80, 0x1e, 0xa9, 0x7e, 0x02, 0x00,
0xb9, 0x9e, 0x28, 0x00, 0x8b, 0x1f, 0x00, 0x00, 0x04, 0x71, 0x99, 0x70, 0x74, 0x0f, 0x28, 0x7c,
0x0a, 0x00, 0x0c, 0xa0, 0x00, 0x23, 0xa9, 0x7e, 0x02, 0x00, 0xb9, 0xae, 0x28, 0x00, 0xeb, 0x28,
0x00, 0x00, 0x06, 0x2e, 0x8b, 0x1f, 0x00, 0x00, 0x0c, 0x20, 0x64, 0x00, 0x4b, 0x07, 0x00, 0x00,
0x38, 0x60, 0x70, 0x0f, 0x08, 0x70, 0xab, 0x8f, 0x2c, 0x70, 0xab, 0x0f, 0xb9, 0x76, 0x04, 0x00,
0x04, 0x61, 0x08, 0x70, 0x00, 0x40, 0xb9, 0x67, 0x70, 0x10, 0xf2, 0x00, 0xc4, 0x30, 0x04, 0x40,
0x04, 0x50, 0x0c, 0x60, 0x20, 0x00, 0x52, 0x03, 0xa6, 0x42, 0x25, 0x50, 0xb4, 0x61, 0x02, 0x06,
0xa6, 0x44, 0x25, 0x55, 0xa6, 0x33, 0x42, 0xf9, 0xf2, 0xfa, 0x06, 0x24, 0x06, 0x35, 0xe1, 0xf0,
0x3d, 0x32, 0x09, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x16, 0x0c, 0x16, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00,
0x64, 0x00, 0x00, 0x00, 0x60, 0x21, 0x06, 0x00, 0x90, 0x00, 0x00, 0x00, 0x18, 0x20, 0x00, 0x00,
0x48, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x30, 0x18, 0x12, 0x00, 0x14, 0xc8, 0x00, 0x00,
0x08, 0x08, 0x00, 0x00, 0x14, 0x64, 0x08, 0x08, 0xe8, 0x03, 0x2c, 0x01, 0x14, 0x32, 0x10, 0x10,
0x20, 0x18, 0x07, 0x00, 0x64, 0x00, 0x64, 0x10, 0x63, 0x07, 0x02, 0x00, 0x32, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x64, 0xc0, 0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xa0, 0x0f, 0x00, 0x00, 0x30, 0x31, 0x83, 0x01, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x80, 0x00, 0x80,
0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0b, 0x16, 0x0c, 0x00, 0x00,
0x00, 0x80, 0x00, 0x80, 0x2c, 0x01, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x2c, 0x01, 0x01, 0x00,
0x00, 0x80, 0x00, 0x00, 0xc8, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0xc8, 0x00, 0x01, 0x00,
0x40, 0xc2, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0xff, 0x00, 0x30, 0x00, 0xff, 0x05, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0xa8, 0x00, 0x10, 0x3f, 0x10, 0x3f, 0x64, 0x3c, 0x10, 0x00,
0x00, 0x00, 0x04, 0x82, 0x00, 0x00, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00,
0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x66, 0x20, 0x00, 0x02, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x03, 0x00, 0x0f, 0x17, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x84, 0x40, 0x00, 0x15, 0x50, 0x80, 0x00, 0x80, 0x40, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xbf,
0x01, 0x20, 0x00, 0x00, 0x0c, 0x0d, 0x0e, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x21, 0x22, 0x23, 0x0b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00, 0xff, 0x00, 0x30, 0x86,
0x00, 0x00, 0x00, 0x52, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x0f, 0x00,
0x50, 0x28, 0x28, 0x00, 0x50, 0x28, 0x28, 0x00, 0x50, 0x28, 0x28, 0x00, 0x50, 0x28, 0x28, 0x00,
0x50, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x2a, 0x28, 0x02,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x26, 0x07, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x80, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x22, 0x09, 0x08, 0x49, 0x26, 0x09, 0x08, 0x51, 0x46, 0x09, 0x08,
0x44, 0x16, 0x09, 0x08, 0x4a, 0x2e, 0x09, 0x08, 0x4d, 0x36, 0x09, 0x08, 0x47, 0x1e, 0x09, 0x08,
0x48, 0x26, 0x09, 0x08, 0x51, 0x46, 0x09, 0x08, 0x44, 0x16, 0x09, 0x08, 0xff, 0xff, 0x0f, 0x00,
0xff, 0xff, 0x0f, 0x00, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x66, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x66, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x66, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x66, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x66, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5c, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5c, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0x75, 0xd6, 0xf9, 0x0c,
0x75, 0xd6, 0xf9, 0x0c, 0x5c, 0x76, 0x39, 0x0a, 0x5d, 0x76, 0x39, 0x0a, 0x68, 0xa6, 0x39, 0x0a,
0x57, 0x5e, 0x39, 0x0a, 0x61, 0x86, 0x39, 0x0a, 0x62, 0x8e, 0x39, 0x0a, 0x5d, 0x76, 0x39, 0x0a,
0x5d, 0x76, 0x39, 0x0a, 0x68, 0xa6, 0x39, 0x0a, 0x58, 0x62, 0x39, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x39, 0x0a, 0x5d, 0x76, 0x39, 0x0a, 0x68, 0xa6, 0x39, 0x0a,
0x57, 0x5e, 0x39, 0x0a, 0x61, 0x86, 0x39, 0x0a, 0x62, 0x8e, 0x39, 0x0a, 0x5c, 0x76, 0x39, 0x0a,
0x5d, 0x76, 0x39, 0x0a, 0x68, 0xa6, 0x39, 0x0a, 0x58, 0x62, 0x39, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0xf8, 0x0a, 0x00, 0x02, 0xf8, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0xc0, 0xf1, 0x3f, 0x21, 0xc0, 0xf1, 0x3f, 0x42, 0xc0, 0xf1, 0x3f,
0x63, 0xc0, 0xf1, 0x3f, 0x84, 0xc0, 0xf1, 0x3f, 0xa5, 0xc0, 0xf1, 0x3f, 0xc6, 0xc0, 0xf1, 0x3f,
0xe7, 0xc0, 0xf1, 0x3f, 0x08, 0xc1, 0xf1, 0x3f, 0x29, 0xc1, 0xf1, 0x3f, 0x4a, 0xc1, 0xf1, 0x3f,
0x6b, 0xc1, 0xf1, 0x3f, 0x8c, 0xc1, 0xf1, 0x3f, 0xad, 0xc1, 0xf1, 0x3f, 0xce, 0xc1, 0xf1, 0x3f,
0xef, 0xc1, 0xf1, 0x3f, 0x10, 0xc2, 0xf1, 0x3f, 0x31, 0xc2, 0xf1, 0x3f, 0x52, 0xc2, 0xf1, 0x3f,
0x73, 0xc2, 0xf1, 0x7f, 0x94, 0xc2, 0xf1, 0x3f, 0xb5, 0xc2, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f,
0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f,
0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x31, 0x28, 0x09, 0x00, 0x2b, 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xff, 0x03, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x18, 0x2e, 0x2e,
0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e,
0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e,
0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e,
0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x19, 0x2e, 0x2e, 0x18, 0x2e, 0x2e,
0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x19, 0x18, 0x2e, 0x19,
0x30, 0x30, 0x30, 0x30, 0x10, 0x10, 0x10, 0x10, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0xcc, 0xcc, 0xcc, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x16, 0x0c, 0x16, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00,
0x64, 0x00, 0x00, 0x00, 0x60, 0x21, 0x06, 0x00, 0x90, 0x00, 0x00, 0x00, 0x18, 0x20, 0x00, 0x00,
0x48, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x30, 0x18, 0x12, 0x00, 0x14, 0xc8, 0x00, 0x00,
0x08, 0x08, 0x00, 0x00, 0x14, 0x64, 0x08, 0x08, 0xe8, 0x03, 0x2c, 0x01, 0x14, 0x32, 0x10, 0x10,
0x20, 0x18, 0x07, 0x00, 0x64, 0x00, 0x64, 0x10, 0x63, 0x07, 0x02, 0x00, 0x32, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x64, 0xc0, 0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xa0, 0x0f, 0x00, 0x00, 0x30, 0x31, 0x83, 0x01, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x80, 0x00, 0x80,
0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0b, 0x17, 0x0f, 0x00, 0x00,
0x00, 0x80, 0x00, 0x80, 0x2c, 0x01, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x2c, 0x01, 0x01, 0x00,
0x00, 0x80, 0x00, 0x00, 0xc8, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0xc8, 0x00, 0x01, 0x00,
0x40, 0xc2, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0xff, 0x00, 0x30, 0x00, 0xff, 0x05, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0xa8, 0x00, 0x10, 0x3f, 0x10, 0x3f, 0x64, 0x3c, 0x10, 0x00,
0x00, 0x00, 0x04, 0x82, 0x00, 0x00, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00,
0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x66, 0x20, 0x00, 0x02, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x03, 0x00, 0x0f, 0x17, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x84, 0x40, 0x00, 0x05, 0x00, 0x80, 0x00, 0x40, 0x40, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xbf,
0x01, 0x20, 0x00, 0x00, 0x0c, 0x0d, 0x0e, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x21, 0x22, 0x23, 0x0b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00, 0xff, 0x00, 0x30, 0x86,
0x00, 0x00, 0x00, 0x52, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x0f, 0x00,
0x50, 0x28, 0x28, 0x00, 0x50, 0x28, 0x28, 0x00, 0x48, 0x29, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x29, 0x28, 0x01,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x26, 0x07, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x80, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x09, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x18, 0x62, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x04, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x19, 0x66, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x27, 0xa2, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x17, 0x62, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x36, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0e, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x27, 0xa2, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x21, 0x8a, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x36, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x04, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x25, 0x9a, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0e, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x27, 0xa2, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0e, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x04, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x21, 0x8a, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0e, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x27, 0xa2, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0e, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0e, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x18, 0x66, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0e, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x04, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x21, 0x8a, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x09, 0x26, 0x08, 0x06,
0x0e, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x21, 0x8a, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x36, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x09, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x07, 0x22, 0x08, 0x06,
0x03, 0x12, 0x08, 0x06, 0x06, 0x1e, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x09, 0x26, 0x08, 0x06,
0x0f, 0x42, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x15, 0x56, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x07, 0x1e, 0x08, 0x06, 0x04, 0x16, 0x08, 0x06,
0x08, 0x22, 0x08, 0x06, 0x01, 0x06, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06,
0x0b, 0x2e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x07, 0x1e, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0xc0, 0xf1, 0x3f, 0x21, 0xc0, 0xf1, 0x3f, 0x42, 0xc0, 0xf1, 0x3f,
0x63, 0xc0, 0xf1, 0x3f, 0x84, 0xc0, 0xf1, 0x3f, 0xa5, 0xc0, 0xf1, 0x3f, 0xc6, 0xc0, 0xf1, 0x3f,
0xe7, 0xc0, 0xf1, 0x3f, 0x08, 0xc1, 0xf1, 0x3f, 0x29, 0xc1, 0xf1, 0x3f, 0x4a, 0xc1, 0xf1, 0x3f,
0x6b, 0xc1, 0xf1, 0x3f, 0x8c, 0xc1, 0xf1, 0x3f, 0xad, 0xc1, 0xf1, 0x3f, 0xce, 0xc1, 0xf1, 0x3f,
0xef, 0xc1, 0xf1, 0x3f, 0x10, 0xc2, 0xf1, 0x3f, 0x31, 0xc2, 0xf1, 0x3f, 0x52, 0xc2, 0xf1, 0x3f,
0x73, 0xc2, 0xf1, 0x7f, 0x94, 0xc2, 0xf1, 0x3f, 0xb5, 0xc2, 0xf1, 0x3b, 0x00, 0xc0, 0xf1, 0x3b,
0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f,
0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x31, 0x28, 0x09, 0x00, 0x2e, 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xff, 0x03, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x2e, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x10, 0x10, 0x10, 0x10, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0xcc, 0xcc, 0xcc, 0x0c, 0x43, 0x4d, 0x43, 0x53, 0x32, 0x54, 0x41, 0x47
};
#endif // __IST30XX_CMCS_BIN_H__

View file

@ -0,0 +1,615 @@
#ifndef __IST30XX_CMCS_BIN_JIT_H__
#define __IST30XX_CMCS_BIN_JIT_H__
/* ist30xx cmcs binary: model( ) */
static unsigned char ist30xx_cmcs_jit[] = {
0x43, 0x4d, 0x43, 0x53, 0x32, 0x54, 0x41, 0x47, 0x02, 0x00, 0x00, 0x00, 0x43, 0x4d, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x1e, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x4e, 0x00, 0x4e, 0x00,
0x43, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
0x4e, 0x00, 0x54, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x11, 0x00, 0x00, 0xac, 0x0d, 0xac, 0x0d,
0x28, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x43, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00,
0x38, 0xff, 0xc8, 0x00, 0xbc, 0x02, 0x14, 0x05, 0xbc, 0x02, 0x32, 0x05, 0x30, 0x02, 0x10, 0x04,
0x20, 0x11, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x08, 0x70, 0x00, 0x40, 0x00, 0x03, 0x00, 0x00,
0x00, 0x40, 0x00, 0x30, 0x00, 0x09, 0x00, 0x00, 0xc4, 0x52, 0x00, 0x30, 0x50, 0x01, 0x00, 0x00,
0x30, 0x11, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x30, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
0x30, 0x1d, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x3d, 0x32, 0x09, 0xd2, 0x60, 0x28, 0xd6, 0x1f,
0x61, 0x18, 0xd4, 0x69, 0x08, 0x01, 0x00, 0x00, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01,
0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xf4, 0x01, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d,
0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xac, 0x0d, 0xf0, 0x0a, 0xe4, 0x0c, 0xf0, 0x0a, 0xe4, 0x0c,
0xc4, 0x09, 0xe4, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x10, 0xa8, 0x10, 0x0c, 0x80, 0x5c, 0x06,
0x2b, 0x2b, 0x00, 0x00, 0xf2, 0xfe, 0x00, 0x00, 0x08, 0x70, 0x00, 0x40, 0x38, 0x67, 0x08, 0x70,
0xb9, 0x67, 0x08, 0x70, 0xe1, 0xf0, 0x00, 0x00, 0x08, 0x60, 0x00, 0x40, 0x38, 0x76, 0x08, 0x70,
0xd6, 0x72, 0x82, 0xfd, 0xe1, 0xf0, 0x00, 0x00, 0x08, 0x60, 0x00, 0x40, 0x38, 0x76, 0x70, 0x70,
0x64, 0x71, 0xb9, 0x76, 0x70, 0x70, 0xe1, 0xf0, 0x08, 0x60, 0x00, 0x40, 0x38, 0x76, 0x70, 0x70,
0x64, 0x72, 0xb9, 0x76, 0x70, 0x70, 0xe1, 0xf0, 0x67, 0x31, 0x14, 0x71, 0x34, 0x31, 0xc6, 0x37,
0x82, 0x04, 0xb1, 0x02, 0x24, 0x24, 0xf2, 0xfb, 0xe1, 0xf0, 0x00, 0x00, 0x77, 0x41, 0x14, 0x71,
0x34, 0x41, 0xc6, 0x47, 0x82, 0x04, 0xb1, 0x32, 0x24, 0x24, 0xf2, 0xfb, 0xe1, 0xf0, 0x00, 0x00,
0xf7, 0x40, 0x04, 0x70, 0xc6, 0x74, 0x82, 0x07, 0x2f, 0x67, 0x07, 0x00, 0x26, 0x62, 0xa1, 0x36,
0x24, 0x71, 0xf2, 0xf9, 0xe1, 0xf0, 0x00, 0x00, 0x04, 0x70, 0xc6, 0x74, 0x82, 0x06, 0x2f, 0x67,
0x02, 0x00, 0x91, 0x36, 0x24, 0x71, 0xf2, 0xfa, 0xe1, 0xf0, 0x00, 0x00, 0x34, 0x14, 0xb1, 0xf1,
0x77, 0x41, 0x04, 0x70, 0x14, 0x61, 0x34, 0x41, 0xc6, 0x46, 0x82, 0x09, 0x2f, 0x57, 0x03, 0x00,
0x30, 0xf5, 0x2f, 0x57, 0x02, 0x00, 0xb1, 0xf5, 0x24, 0x74, 0xf2, 0xf6, 0x30, 0xf1, 0x24, 0x14,
0xe1, 0xf0, 0x00, 0x00, 0x34, 0x14, 0x0c, 0x70, 0x4a, 0x01, 0xb1, 0x71, 0x30, 0x71, 0x14, 0x61,
0xc4, 0x70, 0x26, 0x67, 0xb1, 0x61, 0x92, 0xfb, 0x24, 0x14, 0xe1, 0xf0, 0x34, 0x1c, 0x26, 0x22,
0xc9, 0xe1, 0x04, 0x00, 0x06, 0xe2, 0xb1, 0x01, 0x57, 0xe1, 0xb1, 0x01, 0x26, 0xe2, 0x30, 0x71,
0xc6, 0x7e, 0xb2, 0x07, 0x8b, 0x06, 0x00, 0x00, 0x30, 0x71, 0x24, 0x71, 0xb1, 0x71, 0xf2, 0xf8,
0x48, 0xe1, 0x04, 0x00, 0x24, 0x1c, 0xe1, 0xf0, 0x08, 0x60, 0x00, 0x30, 0x38, 0x76, 0x28, 0x00,
0xd4, 0x74, 0x92, 0xfd, 0xe1, 0xf0, 0x00, 0x00, 0x77, 0x31, 0x04, 0x70, 0x14, 0x61, 0x34, 0x31,
0xc6, 0x36, 0x82, 0x05, 0x30, 0x52, 0x24, 0x24, 0x26, 0x75, 0xf2, 0xfa, 0x06, 0x27, 0xe1, 0xf0,
0x04, 0x6c, 0xa9, 0x60, 0xa6, 0x0f, 0x0c, 0x60, 0x16, 0x00, 0xa9, 0x60, 0xa4, 0x0f, 0x04, 0x6a,
0xa9, 0x60, 0xa2, 0x0f, 0x0c, 0x60, 0x13, 0x00, 0xa9, 0x60, 0xa0, 0x0f, 0x0c, 0x50, 0xee, 0x00,
0x06, 0x76, 0x0c, 0x70, 0x5c, 0x0f, 0xb9, 0x50, 0x5c, 0x0f, 0x0c, 0x60, 0xef, 0x00, 0xb9, 0x67,
0x04, 0x00, 0x0c, 0x60, 0xf3, 0x0c, 0xb9, 0x67, 0x08, 0x00, 0xb9, 0x67, 0x0c, 0x00, 0xb9, 0x67,
0x10, 0x00, 0xe1, 0xf0, 0x3c, 0x10, 0x10, 0x00, 0xd1, 0xc1, 0x06, 0xd3, 0x78, 0x30, 0xa6, 0x0f,
0x06, 0xe2, 0x06, 0xc4, 0xcb, 0x31, 0x00, 0x00, 0x78, 0x60, 0xa2, 0x0f, 0x2f, 0x7d, 0x02, 0x00,
0xc6, 0xd6, 0xb1, 0x7c, 0xa2, 0x12, 0x06, 0x56, 0x0c, 0x50, 0x5c, 0x0f, 0x38, 0x55, 0x04, 0x00,
0x04, 0x20, 0xc6, 0x75, 0x92, 0x03, 0x28, 0x20, 0x7a, 0x0f, 0x38, 0x60, 0x5c, 0x0f, 0xc6, 0x76,
0x92, 0x10, 0x28, 0x20, 0x7a, 0x0f, 0xf2, 0x0d, 0x78, 0x70, 0xa0, 0x0f, 0xc6, 0xe7, 0xb2, 0x04,
0x28, 0x20, 0x78, 0x0f, 0xf2, 0x06, 0x3c, 0xe0, 0x14, 0x00, 0xc4, 0xe1, 0xc2, 0xfa, 0x04, 0x20,
0x50, 0xc1, 0x2c, 0x10, 0x10, 0x00, 0xe1, 0xf0, 0x08, 0x70, 0x0f, 0xc0, 0x2c, 0x70, 0xff, 0xff,
0x08, 0x60, 0x00, 0x40, 0xb9, 0x76, 0x3c, 0x71, 0x08, 0x70, 0x00, 0x30, 0x2c, 0x70, 0x00, 0x40,
0x57, 0x21, 0x2f, 0x57, 0x02, 0x00, 0x30, 0x75, 0xc4, 0x40, 0x0c, 0x60, 0xff, 0x03, 0x56, 0x67,
0x77, 0x75, 0x5c, 0x70, 0xff, 0x03, 0x82, 0x09, 0xc4, 0x30, 0x82, 0x04, 0x26, 0x64, 0x26, 0x74,
0xf2, 0x11, 0x36, 0x74, 0x36, 0x64, 0xf2, 0x0e, 0xc4, 0x30, 0x82, 0x07, 0xc6, 0x76, 0x02, 0x03,
0x24, 0x61, 0xf2, 0x0d, 0x24, 0x71, 0xf2, 0x06, 0xc6, 0x76, 0x02, 0x03, 0x34, 0x71, 0xf2, 0x02,
0x34, 0x61, 0xc4, 0x60, 0x02, 0x06, 0xcc, 0x60, 0xff, 0x03, 0x12, 0x06, 0x04, 0x20, 0xf2, 0x07,
0x14, 0x21, 0x04, 0x61, 0xf2, 0x04, 0x14, 0x21, 0x0c, 0x60, 0xff, 0x03, 0xc4, 0x70, 0x02, 0x08,
0xcc, 0x70, 0xff, 0x03, 0x02, 0x07, 0x14, 0x21, 0x0c, 0x70, 0xff, 0x03, 0xf2, 0x03, 0x14, 0x21,
0x04, 0x71, 0x57, 0x75, 0x66, 0x76, 0xb1, 0x75, 0x08, 0x70, 0x00, 0x40, 0xb9, 0x07, 0x3c, 0x71,
0xe1, 0xf0, 0x00, 0x00, 0x3c, 0x10, 0x24, 0x00, 0xd9, 0xc1, 0x14, 0x00, 0x06, 0xe2, 0x78, 0x20,
0xa0, 0x0f, 0xd9, 0x81, 0x04, 0x00, 0x78, 0x30, 0xa2, 0x0f, 0x24, 0x22, 0xcb, 0x31, 0x00, 0x00,
0x04, 0x92, 0x26, 0x92, 0x23, 0x3e, 0x0c, 0x20, 0xdc, 0x0a, 0x0c, 0x40, 0x10, 0x02, 0xeb, 0x03,
0x00, 0x00, 0x06, 0x2d, 0x0c, 0x20, 0x9c, 0x08, 0x04, 0x30, 0x0c, 0x40, 0x08, 0x01, 0xab, 0x04,
0x00, 0x00, 0x06, 0x2e, 0x0c, 0x20, 0x5c, 0x06, 0x04, 0x31, 0x0c, 0x40, 0x08, 0x01, 0xab, 0x04,
0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x04, 0x61, 0x08, 0x70, 0x00, 0x40, 0x08, 0xa0, 0x00, 0x30,
0xb9, 0x67, 0x00, 0x70, 0x0c, 0xb0, 0x82, 0x00, 0x2c, 0xa0, 0x00, 0x49, 0x04, 0x21, 0x04, 0xd0,
0x2b, 0x01, 0x00, 0x00, 0x06, 0xed, 0x78, 0x70, 0xa4, 0x0f, 0xc6, 0xd7, 0x32, 0x48, 0x04, 0xc0,
0x78, 0x70, 0xa6, 0x0f, 0xc6, 0xc7, 0x32, 0x41, 0x06, 0x2d, 0x06, 0x3c, 0x06, 0x41, 0x0b, 0x0c,
0x00, 0x00, 0x86, 0x62, 0x82, 0x38, 0x30, 0x21, 0x06, 0x72, 0x57, 0x71, 0x26, 0x7a, 0x30, 0x77,
0x0c, 0x80, 0x9c, 0x08, 0x5c, 0x70, 0xff, 0x0f, 0x3f, 0x66, 0x07, 0x00, 0x2f, 0x72, 0x08, 0x00,
0x90, 0xf7, 0x82, 0x04, 0xcc, 0x60, 0x46, 0x00, 0x02, 0x25, 0x0c, 0x30, 0x5c, 0x06, 0x2f, 0x72,
0x03, 0x00, 0x10, 0x57, 0xc4, 0x51, 0x0c, 0x40, 0xdc, 0x0a, 0x2f, 0x52, 0x02, 0x00, 0x92, 0x05,
0xc4, 0x60, 0x22, 0x0e, 0x91, 0x07, 0xf2, 0x0c, 0xc4, 0x60, 0x12, 0x0a, 0x04, 0x61, 0x91, 0x67,
0x2f, 0x75, 0x04, 0x00, 0xa0, 0x77, 0x92, 0x04, 0x26, 0x82, 0x24, 0xf1, 0x91, 0xf8, 0x26, 0x54,
0x20, 0x45, 0x26, 0x32, 0x10, 0x33, 0xf7, 0x40, 0xa1, 0x45, 0x2b, 0x0f, 0x00, 0x00, 0xc4, 0x20,
0x32, 0x02, 0x24, 0xe1, 0x24, 0xc1, 0xf2, 0xbd, 0x24, 0xd1, 0xf2, 0xb6, 0xc6, 0xe9, 0xb2, 0x0b,
0xb4, 0xb1, 0x82, 0x09, 0xab, 0x00, 0x00, 0x00, 0x04, 0x61, 0x08, 0x70, 0x00, 0x40, 0xb9, 0x67,
0x00, 0x70, 0xf2, 0xa5, 0x58, 0xc1, 0x14, 0x00, 0x58, 0x81, 0x04, 0x00, 0x2c, 0x10, 0x24, 0x00,
0xe1, 0xf0, 0x00, 0x00, 0x34, 0x18, 0x08, 0x70, 0x0f, 0xc0, 0xc1, 0xe1, 0x2c, 0x70, 0xff, 0xff,
0x08, 0xe0, 0x00, 0x40, 0xb9, 0x7e, 0x3c, 0x71, 0x28, 0x70, 0x76, 0x0f, 0x08, 0x20, 0x00, 0x30,
0x06, 0x37, 0x57, 0x35, 0x2c, 0x20, 0x00, 0x40, 0x66, 0x37, 0x0c, 0x40, 0x00, 0x09, 0x4b, 0x03,
0x00, 0x00, 0xb9, 0x0e, 0x3c, 0x71, 0x0c, 0x20, 0x00, 0x02, 0x0b, 0x14, 0x00, 0x00, 0x40, 0xe1,
0x24, 0x18, 0xe1, 0xf0, 0x3c, 0x10, 0x20, 0x00, 0xd9, 0xc1, 0x10, 0x00, 0xd1, 0x81, 0x08, 0xe0,
0x00, 0x30, 0x38, 0x6e, 0x6c, 0x53, 0x0c, 0x70, 0x74, 0x0f, 0xb9, 0x67, 0x08, 0x00, 0x38, 0x6e,
0x70, 0x53, 0x0c, 0xc0, 0x6c, 0x53, 0xb9, 0x67, 0x0c, 0x00, 0x38, 0x6e, 0x74, 0x53, 0x06, 0xd2,
0xb9, 0x67, 0x10, 0x00, 0x38, 0x6e, 0x78, 0x53, 0x26, 0xce, 0xb9, 0x67, 0x14, 0x00, 0x38, 0x6e,
0x7c, 0x53, 0xb9, 0x67, 0x18, 0x00, 0x38, 0x6e, 0x80, 0x53, 0xb9, 0x67, 0x1c, 0x00, 0x38, 0x6e,
0x84, 0x53, 0xb9, 0x67, 0x20, 0x00, 0x38, 0x6e, 0x88, 0x53, 0xb9, 0x67, 0x24, 0x00, 0xb9, 0x0e,
0x6c, 0x53, 0xb9, 0x0e, 0x7c, 0x53, 0xb9, 0x0e, 0x70, 0x53, 0xb9, 0x0e, 0x80, 0x53, 0xb9, 0x0e,
0x74, 0x53, 0xb9, 0x0e, 0x84, 0x53, 0xb9, 0x0e, 0x78, 0x53, 0xb9, 0x0e, 0x88, 0x53, 0x8b, 0x1d,
0x00, 0x00, 0x06, 0x6d, 0x06, 0x7c, 0x2c, 0xe0, 0x7c, 0x53, 0x38, 0x56, 0x08, 0x00, 0xb1, 0x57,
0x90, 0x5d, 0x92, 0x05, 0x38, 0x56, 0x18, 0x00, 0xb9, 0x57, 0x10, 0x00, 0x24, 0x74, 0xc6, 0x7e,
0x24, 0x64, 0x92, 0xf4, 0xab, 0x01, 0x00, 0x00, 0x04, 0xcb, 0x2b, 0x02, 0x00, 0x00, 0x04, 0xb1,
0x08, 0xe0, 0x00, 0x40, 0xb4, 0xc1, 0x82, 0x09, 0xab, 0x00, 0x00, 0x00, 0x04, 0x21, 0xb9, 0xbe,
0x00, 0x70, 0x2b, 0x01, 0x00, 0x00, 0xf2, 0xf7, 0x08, 0xb0, 0x00, 0x30, 0x2c, 0xb0, 0x00, 0x49,
0x78, 0x70, 0xa4, 0x0f, 0xc6, 0xc7, 0x32, 0x27, 0x04, 0xe0, 0x78, 0x30, 0xa6, 0x0f, 0xc6, 0xe3,
0x32, 0x20, 0x06, 0x2c, 0xcb, 0x31, 0x00, 0x00, 0x90, 0x5d, 0x38, 0x6d, 0x28, 0x00, 0x26, 0x2e,
0x2f, 0x72, 0x02, 0x00, 0x26, 0x67, 0x57, 0x21, 0x92, 0x0d, 0x26, 0x2b, 0x30, 0x72, 0x28, 0x4d,
0x04, 0x00, 0x5c, 0x70, 0xff, 0x0f, 0x3f, 0x77, 0x04, 0x00, 0xc4, 0x70, 0x32, 0x07, 0x06, 0x75,
0xf2, 0x05, 0x26, 0x2b, 0x30, 0x72, 0x5c, 0x70, 0xff, 0x0f, 0xa1, 0x76, 0x24, 0xe1, 0xf2, 0xde,
0x24, 0xc1, 0xf2, 0xd7, 0x58, 0xc1, 0x10, 0x00, 0x50, 0x81, 0x2c, 0x10, 0x20, 0x00, 0xe1, 0xf0,
0x08, 0x20, 0x00, 0x40, 0x34, 0x18, 0x2c, 0x20, 0x08, 0x70, 0x0c, 0x30, 0x38, 0x11, 0x0c, 0x40,
0xf8, 0x02, 0xc1, 0xe1, 0x4b, 0x05, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x40, 0x08, 0xe0, 0x00, 0x30,
0x26, 0x2e, 0x0c, 0x30, 0x30, 0x14, 0x0c, 0x40, 0x00, 0x09, 0x4b, 0x05, 0x00, 0x00, 0x0c, 0x20,
0xc4, 0x52, 0x26, 0x2e, 0x0c, 0x30, 0x30, 0x1d, 0x0c, 0x40, 0x50, 0x01, 0x4b, 0x05, 0x00, 0x00,
0x40, 0xe1, 0x24, 0x18, 0xe1, 0xf0, 0x00, 0x00, 0x3c, 0x10, 0x20, 0x00, 0xd1, 0x81, 0x08, 0x70,
0x00, 0x30, 0xd9, 0xc1, 0x10, 0x00, 0x2c, 0x70, 0x00, 0x01, 0x06, 0x29, 0x0c, 0x20, 0x80, 0x1e,
0x0c, 0x30, 0x80, 0x04, 0xb9, 0x70, 0x70, 0x0f, 0xab, 0x02, 0x00, 0x00, 0x06, 0x2a, 0x0c, 0x20,
0x00, 0x23, 0x0c, 0x30, 0x80, 0x04, 0xab, 0x02, 0x00, 0x00, 0xab, 0x08, 0x00, 0x00, 0x38, 0x30,
0x20, 0x11, 0x38, 0xe0, 0x70, 0x0f, 0x04, 0x20, 0x06, 0xc7, 0x0c, 0xc0, 0x20, 0x11, 0x2b, 0x09,
0x00, 0x00, 0xb1, 0x2e, 0x0c, 0x20, 0x30, 0x11, 0x0c, 0x30, 0x80, 0x1e, 0x36, 0x32, 0x2b, 0x09,
0x00, 0x00, 0xb9, 0x2e, 0x08, 0x00, 0x38, 0x7c, 0x04, 0x00, 0x06, 0xeb, 0x0c, 0xe0, 0x74, 0x0f,
0xa9, 0x7e, 0x04, 0x00, 0x77, 0x78, 0xa9, 0x7e, 0x06, 0x00, 0xeb, 0x09, 0x00, 0x00, 0x38, 0x7c,
0x08, 0x00, 0x99, 0x00, 0x74, 0x0f, 0x06, 0x2e, 0x0c, 0x90, 0x80, 0x1e, 0xa9, 0x7e, 0x02, 0x00,
0xb9, 0x9e, 0x28, 0x00, 0x8b, 0x1f, 0x00, 0x00, 0x04, 0x71, 0x99, 0x70, 0x74, 0x0f, 0x28, 0x7c,
0x0a, 0x00, 0x0c, 0xa0, 0x00, 0x23, 0xa9, 0x7e, 0x02, 0x00, 0xb9, 0xae, 0x28, 0x00, 0xeb, 0x28,
0x00, 0x00, 0x06, 0x2e, 0x8b, 0x1f, 0x00, 0x00, 0x0c, 0x20, 0x64, 0x00, 0x4b, 0x07, 0x00, 0x00,
0x38, 0x60, 0x70, 0x0f, 0x08, 0x70, 0xab, 0x8f, 0x2c, 0x70, 0xab, 0x0f, 0xb9, 0x76, 0x04, 0x00,
0x04, 0x61, 0x08, 0x70, 0x00, 0x40, 0xb9, 0x67, 0x70, 0x10, 0xf2, 0x00, 0xc4, 0x30, 0x04, 0x40,
0x04, 0x50, 0x0c, 0x60, 0x20, 0x00, 0x52, 0x03, 0xa6, 0x42, 0x25, 0x50, 0xb4, 0x61, 0x02, 0x06,
0xa6, 0x44, 0x25, 0x55, 0xa6, 0x33, 0x42, 0xf9, 0xf2, 0xfa, 0x06, 0x24, 0x06, 0x35, 0xe1, 0xf0,
0x3d, 0x32, 0x09, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x16, 0x0c, 0x16, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00,
0x64, 0x00, 0x00, 0x00, 0x60, 0x21, 0x06, 0x00, 0x90, 0x00, 0x00, 0x00, 0x18, 0x20, 0x00, 0x00,
0x48, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x30, 0x18, 0x12, 0x00, 0x14, 0xc8, 0x00, 0x00,
0x08, 0x08, 0x00, 0x00, 0x14, 0x64, 0x08, 0x08, 0xe8, 0x03, 0x2c, 0x01, 0x14, 0x32, 0x10, 0x10,
0x20, 0x18, 0x07, 0x00, 0x64, 0x00, 0x64, 0x10, 0x63, 0x07, 0x02, 0x00, 0x32, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x64, 0xc0, 0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xa0, 0x0f, 0x00, 0x00, 0x30, 0x31, 0x83, 0x01, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x80, 0x00, 0x80,
0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0b, 0x16, 0x0c, 0x00, 0x00,
0x00, 0x80, 0x00, 0x80, 0x2c, 0x01, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x2c, 0x01, 0x01, 0x00,
0x00, 0x80, 0x00, 0x00, 0xc8, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0xc8, 0x00, 0x01, 0x00,
0x40, 0xc2, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0xff, 0x00, 0x30, 0x00, 0xff, 0x05, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0xa8, 0x00, 0x10, 0x3f, 0x10, 0x3f, 0x64, 0x3c, 0x10, 0x00,
0x00, 0x00, 0x04, 0x82, 0x00, 0x00, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00,
0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x66, 0x20, 0x00, 0x02, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x03, 0x00, 0x0f, 0x17, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x84, 0x40, 0x00, 0x15, 0x50, 0x80, 0x00, 0x80, 0x40, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xbf,
0x01, 0x20, 0x00, 0x00, 0x0c, 0x0d, 0x0e, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x21, 0x22, 0x23, 0x0b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00, 0xff, 0x00, 0x30, 0x86,
0x00, 0x00, 0x00, 0x52, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x0f, 0x00,
0x50, 0x28, 0x28, 0x00, 0x50, 0x28, 0x28, 0x00, 0x50, 0x28, 0x28, 0x00, 0x50, 0x28, 0x28, 0x00,
0x50, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x2a, 0x28, 0x02,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x26, 0x07, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x80, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x22, 0x09, 0x08, 0x49, 0x26, 0x09, 0x08, 0x51, 0x46, 0x09, 0x08,
0x44, 0x16, 0x09, 0x08, 0x4a, 0x2e, 0x09, 0x08, 0x4d, 0x36, 0x09, 0x08, 0x47, 0x1e, 0x09, 0x08,
0x48, 0x26, 0x09, 0x08, 0x51, 0x46, 0x09, 0x08, 0x44, 0x16, 0x09, 0x08, 0xff, 0xff, 0x0f, 0x00,
0xff, 0xff, 0x0f, 0x00, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x66, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x66, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x66, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x66, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x66, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5c, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5c, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x57, 0x5e, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x63, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x09, 0x0a, 0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a,
0x57, 0x5e, 0x09, 0x0a, 0x61, 0x86, 0x09, 0x0a, 0x62, 0x8e, 0x09, 0x0a, 0x5c, 0x76, 0x09, 0x0a,
0x5d, 0x76, 0x09, 0x0a, 0x68, 0xa6, 0x09, 0x0a, 0x58, 0x62, 0x09, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0xff, 0xff, 0x0f, 0x0a, 0x75, 0xd6, 0xf9, 0x0c,
0x75, 0xd6, 0xf9, 0x0c, 0x5c, 0x76, 0x39, 0x0a, 0x5d, 0x76, 0x39, 0x0a, 0x68, 0xa6, 0x39, 0x0a,
0x57, 0x5e, 0x39, 0x0a, 0x61, 0x86, 0x39, 0x0a, 0x62, 0x8e, 0x39, 0x0a, 0x5d, 0x76, 0x39, 0x0a,
0x5d, 0x76, 0x39, 0x0a, 0x68, 0xa6, 0x39, 0x0a, 0x58, 0x62, 0x39, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x5c, 0x76, 0x39, 0x0a, 0x5d, 0x76, 0x39, 0x0a, 0x68, 0xa6, 0x39, 0x0a,
0x57, 0x5e, 0x39, 0x0a, 0x61, 0x86, 0x39, 0x0a, 0x62, 0x8e, 0x39, 0x0a, 0x5c, 0x76, 0x39, 0x0a,
0x5d, 0x76, 0x39, 0x0a, 0x68, 0xa6, 0x39, 0x0a, 0x58, 0x62, 0x39, 0x0a, 0xff, 0xff, 0x0f, 0x0a,
0xff, 0xff, 0x0f, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0xf8, 0x0a, 0x00, 0x02, 0xf8, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0xc0, 0xf1, 0x3f, 0x21, 0xc0, 0xf1, 0x3f, 0x42, 0xc0, 0xf1, 0x3f,
0x63, 0xc0, 0xf1, 0x3f, 0x84, 0xc0, 0xf1, 0x3f, 0xa5, 0xc0, 0xf1, 0x3f, 0xc6, 0xc0, 0xf1, 0x3f,
0xe7, 0xc0, 0xf1, 0x3f, 0x08, 0xc1, 0xf1, 0x3f, 0x29, 0xc1, 0xf1, 0x3f, 0x4a, 0xc1, 0xf1, 0x3f,
0x6b, 0xc1, 0xf1, 0x3f, 0x8c, 0xc1, 0xf1, 0x3f, 0xad, 0xc1, 0xf1, 0x3f, 0xce, 0xc1, 0xf1, 0x3f,
0xef, 0xc1, 0xf1, 0x3f, 0x10, 0xc2, 0xf1, 0x3f, 0x31, 0xc2, 0xf1, 0x3f, 0x52, 0xc2, 0xf1, 0x3f,
0x73, 0xc2, 0xf1, 0x7f, 0x94, 0xc2, 0xf1, 0x3f, 0xb5, 0xc2, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f,
0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f,
0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x31, 0x28, 0x09, 0x00, 0x2b, 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xff, 0x03, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x18, 0x2e, 0x2e,
0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e,
0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e,
0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e,
0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x19, 0x2e, 0x2e, 0x18, 0x2e, 0x2e,
0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x2e, 0x18, 0x2e, 0x2e, 0x19, 0x18, 0x2e, 0x19,
0x30, 0x30, 0x30, 0x30, 0x10, 0x10, 0x10, 0x10, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0xcc, 0xcc, 0xcc, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x16, 0x0c, 0x16, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00,
0x64, 0x00, 0x00, 0x00, 0x60, 0x21, 0x06, 0x00, 0x90, 0x00, 0x00, 0x00, 0x18, 0x20, 0x00, 0x00,
0x48, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x30, 0x18, 0x12, 0x00, 0x14, 0xc8, 0x00, 0x00,
0x08, 0x08, 0x00, 0x00, 0x14, 0x64, 0x08, 0x08, 0xe8, 0x03, 0x2c, 0x01, 0x14, 0x32, 0x10, 0x10,
0x20, 0x18, 0x07, 0x00, 0x64, 0x00, 0x64, 0x10, 0x63, 0x07, 0x02, 0x00, 0x32, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x64, 0xc0, 0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0xa0, 0x0f, 0x00, 0x00, 0x30, 0x31, 0x83, 0x01, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x80, 0x00, 0x80,
0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0b, 0x17, 0x0f, 0x00, 0x00,
0x00, 0x80, 0x00, 0x80, 0x2c, 0x01, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x2c, 0x01, 0x01, 0x00,
0x00, 0x80, 0x00, 0x00, 0xc8, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0xc8, 0x00, 0x01, 0x00,
0x40, 0xc2, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0xff, 0x00, 0x30, 0x00, 0xff, 0x05, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0xa8, 0x00, 0x10, 0x3f, 0x10, 0x3f, 0x64, 0x3c, 0x10, 0x00,
0x00, 0x00, 0x04, 0x82, 0x00, 0x00, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00,
0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x66, 0x20, 0x00, 0x02, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x03, 0x00, 0x0f, 0x17, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x84, 0x40, 0x00, 0x05, 0x00, 0x80, 0x00, 0x40, 0x40, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xbf,
0x01, 0x20, 0x00, 0x00, 0x0c, 0x0d, 0x0e, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x21, 0x22, 0x23, 0x0b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00, 0xff, 0x00, 0x30, 0x86,
0x00, 0x00, 0x00, 0x52, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x0f, 0x00,
0x50, 0x28, 0x28, 0x00, 0x50, 0x28, 0x28, 0x00, 0x48, 0x29, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x29, 0x28, 0x01,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x26, 0x07, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x80, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x09, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x18, 0x62, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x04, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x19, 0x66, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x27, 0xa2, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x17, 0x62, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x36, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0e, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x27, 0xa2, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x21, 0x8a, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x36, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x04, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x25, 0x9a, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0e, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x27, 0xa2, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0e, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x04, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x21, 0x8a, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0e, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x27, 0xa2, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0e, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0e, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x18, 0x66, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x06, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0e, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x04, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x21, 0x8a, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x09, 0x26, 0x08, 0x06,
0x0e, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x21, 0x8a, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x36, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x08, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x05, 0x1a, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x09, 0x26, 0x08, 0x06,
0x0f, 0x3e, 0x08, 0x06, 0x01, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x17, 0x5e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0d, 0x3a, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x07, 0x22, 0x08, 0x06,
0x03, 0x12, 0x08, 0x06, 0x06, 0x1e, 0x08, 0x06, 0x0f, 0x3e, 0x08, 0x06, 0x09, 0x26, 0x08, 0x06,
0x0f, 0x42, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x03, 0x0e, 0x08, 0x06,
0x15, 0x56, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x0e, 0x3e, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x03, 0x12, 0x08, 0x06, 0x07, 0x1e, 0x08, 0x06, 0x04, 0x16, 0x08, 0x06,
0x08, 0x22, 0x08, 0x06, 0x01, 0x06, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06, 0x02, 0x0a, 0x08, 0x06,
0x0b, 0x2e, 0x08, 0x06, 0xff, 0x01, 0x08, 0x06, 0x07, 0x1e, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06, 0x00, 0x02, 0x08, 0x06,
0x00, 0x02, 0x08, 0x06, 0x00, 0xc0, 0xf1, 0x3f, 0x21, 0xc0, 0xf1, 0x3f, 0x42, 0xc0, 0xf1, 0x3f,
0x63, 0xc0, 0xf1, 0x3f, 0x84, 0xc0, 0xf1, 0x3f, 0xa5, 0xc0, 0xf1, 0x3f, 0xc6, 0xc0, 0xf1, 0x3f,
0xe7, 0xc0, 0xf1, 0x3f, 0x08, 0xc1, 0xf1, 0x3f, 0x29, 0xc1, 0xf1, 0x3f, 0x4a, 0xc1, 0xf1, 0x3f,
0x6b, 0xc1, 0xf1, 0x3f, 0x8c, 0xc1, 0xf1, 0x3f, 0xad, 0xc1, 0xf1, 0x3f, 0xce, 0xc1, 0xf1, 0x3f,
0xef, 0xc1, 0xf1, 0x3f, 0x10, 0xc2, 0xf1, 0x3f, 0x31, 0xc2, 0xf1, 0x3f, 0x52, 0xc2, 0xf1, 0x3f,
0x73, 0xc2, 0xf1, 0x7f, 0x94, 0xc2, 0xf1, 0x3f, 0xb5, 0xc2, 0xf1, 0x3b, 0x00, 0xc0, 0xf1, 0x3b,
0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f,
0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x31, 0x28, 0x09, 0x00, 0x2e, 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xff, 0x03, 0x00, 0x00,
0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x2e, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x10, 0x10, 0x10, 0x10, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0xcc, 0xcc, 0xcc, 0x0c, 0x43, 0x4d, 0x43, 0x53, 0x32, 0x54, 0x41, 0x47
};
#endif // __IST30XX_CMCS_BIN_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,134 @@
/*
* Copyright (C) 2010, Imagis Technology Co. Ltd. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __IST30XXC_CMCS_JIT_H__
#define __IST30XXC_CMCS_JIT_H__
#define CMCS_MSG_MASK (0xFFFFFFF0)
#define CM_MSG_VALID (0x0E7DC770)
#define CS_MSG_VALID (0x0E7DC500)
#define IST30XX_CMCS_JIT_NAME "ist30xxc_jit.cms"
#define IST30XX_CMCS_JIT_MAGIC "CMCS2TAG"
struct CMCS_JIT_SPEC_NODE {
u32 node_cnt;
u16 *buf_min;
u16 *buf_max;
};
struct CMCS_JIT_SPEC_TOTAL {
s16 screen_min;
s16 screen_max;
s16 gtx_min;
s16 gtx_max;
s16 key_min;
s16 key_max;
};
struct CMCS_JIT_ITEM_INFO {
char name[8];
u32 addr;
u32 size;
char data_type[2];
char spec_type[2];
};
typedef struct _CMCS_JIT_ITEM {
u32 cnt;
struct CMCS_JIT_ITEM_INFO *item;
} CMCS_JIT_ITEM;
struct CMCS_JIT_CMD_INFO {
u32 addr;
u32 value;
};
typedef struct _CMCS_JIT_CMD {
u32 cnt;
struct CMCS_JIT_CMD_INFO *cmd;
} CMCS_JIT_CMD;
union CMCS_JIT_SPEC_ITEM {
struct CMCS_JIT_SPEC_NODE spec_node;
struct CMCS_JIT_SPEC_TOTAL spec_total;
};
struct CMCS_JIT_SPEC_SLOPE {
char name[8];
s16 x_min;
s16 x_max;
s16 gtx_x_min;
s16 gtx_x_max;
s16 y_min;
s16 y_max;
s16 gtx_y_min;
s16 gtx_y_max;
s16 key_min;
s16 key_max;
};
struct CMCS_JIT_REG_INFO {
char name[8];
u32 addr;
u32 size;
};
typedef struct _CMCS_JIT_PARAM {
u32 cmcs_size_addr;
u32 cmcs_size;
u32 enable_addr;
u32 checksum_addr;
u32 end_notify_addr;
u32 sensor1_addr;
u32 sensor2_addr;
u32 sensor3_addr;
u32 cm_sensor1_size;
u32 cm_sensor2_size;
u32 cm_sensor3_size;
u32 cs_sensor1_size;
u32 cs_sensor2_size;
u32 cs_sensor3_size;
u32 cmcs_chksum;
u32 cm_sensor_chksum;
u32 cs_sensor_chksum;
} CMCS_JIT_PARAM;
typedef struct _CMCS_JIT_BIN_INFO {
char magic1[8];
CMCS_JIT_ITEM items;
CMCS_JIT_CMD cmds;
struct CMCS_JIT_SPEC_SLOPE spec_slope;
struct CMCS_JIT_SPEC_TOTAL spec_cr;
CMCS_JIT_PARAM param;
union CMCS_JIT_SPEC_ITEM *spec_item;
u8 *buf_cmcs;
u32 *buf_cm_sensor;
u32 *buf_cs_sensor;
char magic2[8];
} CMCS_JIT_BIN_INFO;
typedef struct _CMCS_JIT_BUF {
s16 cm[IST30XX_NODE_TOTAL_NUM];
s16 cm_jit[IST30XX_NODE_TOTAL_NUM];
s16 spec_min[IST30XX_NODE_TOTAL_NUM];
s16 spec_max[IST30XX_NODE_TOTAL_NUM];
s16 slope0[IST30XX_NODE_TOTAL_NUM];
s16 slope1[IST30XX_NODE_TOTAL_NUM];
s16 cs[IST30XX_NODE_TOTAL_NUM];
} CMCS_JIT_BUF;
int ist30xx_init_cmcs_jit_sysfs(struct ist30xx_data *data);
#endif // __IST30XXC_CMCS_H__

View file

@ -0,0 +1,631 @@
#ifndef __IST30XXC_CMCS_JIT_BIN_H__
#define __IST30XXC_CMCS_JIT_BIN_H__
/* ist30xx cmcs binary: model( ) */
static unsigned char ist30xx_cmcs_jit[] = {
0x43, 0x4d, 0x43, 0x53, 0x32, 0x54, 0x41, 0x47, 0x03, 0x00, 0x00, 0x00, 0x43, 0x4d, 0x4a, 0x49,
0x54, 0x00, 0x00, 0x00, 0x80, 0x1e, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00,
0x43, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
0x4e, 0x00, 0x4e, 0x00, 0x43, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00,
0x80, 0x04, 0x00, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x19, 0x00, 0x00,
0x02, 0x01, 0x00, 0x00, 0xe8, 0x19, 0x00, 0x00, 0x0e, 0x16, 0x0c, 0x14, 0xec, 0x19, 0x00, 0x00,
0x0c, 0x14, 0x0d, 0x14, 0xf0, 0x19, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x19, 0x00, 0x00,
0xff, 0xff, 0x15, 0xff, 0xf8, 0x19, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0xfc, 0x19, 0x00, 0x00,
0xac, 0x0d, 0xac, 0x0d, 0x43, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xff, 0xc8, 0x00,
0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00,
0x78, 0x05, 0x98, 0x08, 0x78, 0x05, 0x98, 0x08, 0x78, 0x05, 0x98, 0x08, 0xe0, 0x19, 0x00, 0x00,
0x3c, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x30, 0x08, 0x01, 0x00, 0x30, 0x04, 0x01, 0x00, 0x30,
0x08, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x30, 0xc4, 0x52, 0x00, 0x30, 0x00, 0x03, 0x00, 0x00,
0x00, 0x09, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
0x50, 0x01, 0x00, 0x00, 0x4a, 0xdc, 0xc5, 0x0d, 0x18, 0x79, 0x84, 0x54, 0x22, 0xc4, 0xa5, 0x15,
0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00, 0x38, 0xff, 0xc8, 0x00, 0xfe, 0x00, 0x00, 0x00,
0x6d, 0x04, 0x46, 0x04, 0x20, 0x04, 0xf9, 0x03, 0xc6, 0x03, 0xa3, 0x03, 0x99, 0x03, 0x9f, 0x03,
0xbb, 0x03, 0x48, 0x04, 0xe3, 0x03, 0xda, 0x03, 0x0c, 0x04, 0xff, 0x03, 0xe4, 0x03, 0xcd, 0x03,
0xab, 0x03, 0x92, 0x03, 0x7d, 0x03, 0x73, 0x03, 0xa6, 0x03, 0xbb, 0x03, 0xa6, 0x03, 0xa4, 0x03,
0xa9, 0x03, 0x98, 0x03, 0x9d, 0x03, 0x92, 0x03, 0x8b, 0x03, 0x81, 0x03, 0x6c, 0x03, 0x51, 0x03,
0x5b, 0x03, 0x62, 0x03, 0x57, 0x03, 0x38, 0x03, 0x4e, 0x04, 0x48, 0x04, 0x46, 0x04, 0x3b, 0x04,
0x26, 0x04, 0x2a, 0x04, 0x0c, 0x04, 0xf3, 0x03, 0xf6, 0x03, 0xf9, 0x03, 0xec, 0x03, 0xdc, 0x03,
0x34, 0x04, 0x26, 0x04, 0x32, 0x04, 0x25, 0x04, 0x16, 0x04, 0x0f, 0x04, 0xf3, 0x03, 0xdc, 0x03,
0xe8, 0x03, 0xf5, 0x03, 0x13, 0x04, 0xad, 0x03, 0x01, 0x04, 0xfe, 0x03, 0x07, 0x04, 0xfe, 0x03,
0xef, 0x03, 0xeb, 0x03, 0xcf, 0x03, 0xb7, 0x03, 0xbb, 0x03, 0xba, 0x03, 0xae, 0x03, 0x99, 0x03,
0x1b, 0x04, 0x0f, 0x04, 0x1a, 0x04, 0x11, 0x04, 0x03, 0x04, 0xfc, 0x03, 0xe3, 0x03, 0xc7, 0x03,
0xd0, 0x03, 0xd8, 0x03, 0x07, 0x04, 0x95, 0x03, 0xc4, 0x03, 0xc5, 0x03, 0xca, 0x03, 0xc3, 0x03,
0xb6, 0x03, 0xb4, 0x03, 0x9b, 0x03, 0x84, 0x03, 0x88, 0x03, 0x83, 0x03, 0x76, 0x03, 0x68, 0x03,
0x03, 0x04, 0xf6, 0x03, 0xfd, 0x03, 0xf5, 0x03, 0xe7, 0x03, 0xe4, 0x03, 0xcd, 0x03, 0xb2, 0x03,
0xb8, 0x03, 0xb1, 0x03, 0xab, 0x03, 0x7c, 0x03, 0x05, 0x04, 0x09, 0x04, 0x11, 0x04, 0x0a, 0x04,
0xfb, 0x03, 0xf8, 0x03, 0xe0, 0x03, 0xc3, 0x03, 0xcb, 0x03, 0xc4, 0x03, 0xb6, 0x03, 0xa8, 0x03,
0x30, 0x04, 0x22, 0x04, 0x2d, 0x04, 0x25, 0x04, 0x17, 0x04, 0x13, 0x04, 0xf7, 0x03, 0xdb, 0x03,
0xe4, 0x03, 0xda, 0x03, 0xcf, 0x03, 0x9c, 0x03, 0x31, 0x04, 0x42, 0x04, 0x4c, 0x04, 0x48, 0x04,
0x38, 0x04, 0x36, 0x04, 0x18, 0x04, 0xfa, 0x03, 0x04, 0x04, 0xfa, 0x03, 0xeb, 0x03, 0xde, 0x03,
0x34, 0x04, 0x26, 0x04, 0x33, 0x04, 0x2f, 0x04, 0x1c, 0x04, 0x16, 0x04, 0xfd, 0x03, 0xe2, 0x03,
0xe9, 0x03, 0xe3, 0x03, 0xd4, 0x03, 0x94, 0x03, 0x4f, 0x04, 0x3a, 0x04, 0x44, 0x04, 0x41, 0x04,
0x2f, 0x04, 0x2a, 0x04, 0x0e, 0x04, 0xf1, 0x03, 0xfa, 0x03, 0xf3, 0x03, 0xe3, 0x03, 0xd0, 0x03,
0xe0, 0x03, 0xd6, 0x03, 0xe3, 0x03, 0xda, 0x03, 0xd4, 0x03, 0xc9, 0x03, 0xb1, 0x03, 0x95, 0x03,
0x9e, 0x03, 0x91, 0x03, 0x8d, 0x03, 0x7d, 0x03, 0x26, 0x04, 0x1d, 0x04, 0x29, 0x04, 0x25, 0x04,
0x18, 0x04, 0x13, 0x04, 0xf4, 0x03, 0xd6, 0x03, 0xdf, 0x03, 0xd5, 0x03, 0xc9, 0x03, 0xb3, 0x03,
0x09, 0x04, 0x02, 0x04, 0x10, 0x04, 0x09, 0x04, 0xfe, 0x03, 0xf8, 0x03, 0xda, 0x03, 0xbc, 0x03,
0xc5, 0x03, 0xba, 0x03, 0xb2, 0x03, 0x97, 0x03, 0xc0, 0x03, 0x9e, 0x03, 0xab, 0x03, 0xae, 0x03,
0xa1, 0x03, 0x8f, 0x03, 0x73, 0x03, 0x68, 0x03, 0x6a, 0x03, 0x55, 0x03, 0x3b, 0x03, 0x8c, 0x03,
0xee, 0x03, 0x6d, 0x03, 0x71, 0x03, 0x6b, 0x03, 0x5f, 0x03, 0x5a, 0x03, 0x5c, 0x03, 0x41, 0x03,
0x3e, 0x03, 0x2e, 0x03, 0x2a, 0x03, 0x55, 0x03, 0xd6, 0x03, 0x66, 0x03, 0x68, 0x03, 0x6d, 0x03,
0x62, 0x03, 0x57, 0x03, 0x27, 0x03, 0x1a, 0x03, 0x1a, 0x03, 0x17, 0x03, 0x14, 0x03, 0x65, 0x03,
0xb4, 0x03, 0xd5, 0x03, 0xdd, 0x03, 0xd9, 0x03, 0xca, 0x03, 0xc7, 0x03, 0xbb, 0x03, 0x9b, 0x03,
0x9f, 0x03, 0x96, 0x03, 0x89, 0x03, 0x4c, 0x03, 0xfe, 0x03, 0xeb, 0x02, 0x61, 0x07, 0x20, 0x07,
0xe0, 0x06, 0x9e, 0x06, 0x4a, 0x06, 0x10, 0x06, 0x00, 0x06, 0x09, 0x06, 0x37, 0x06, 0x22, 0x07,
0x7a, 0x06, 0x6c, 0x06, 0xbf, 0x06, 0xa8, 0x06, 0x7d, 0x06, 0x55, 0x06, 0x1d, 0x06, 0xf3, 0x05,
0xd0, 0x05, 0xc0, 0x05, 0x14, 0x06, 0x37, 0x06, 0x14, 0x06, 0x11, 0x06, 0x19, 0x06, 0xfd, 0x05,
0x06, 0x06, 0xf4, 0x05, 0xe7, 0x05, 0xd7, 0x05, 0xb5, 0x05, 0x87, 0x05, 0x98, 0x05, 0xa3, 0x05,
0x92, 0x05, 0x5e, 0x05, 0x2d, 0x07, 0x23, 0x07, 0x1f, 0x07, 0x0d, 0x07, 0xea, 0x06, 0xf1, 0x06,
0xbf, 0x06, 0x94, 0x06, 0x9b, 0x06, 0x9f, 0x06, 0x8a, 0x06, 0x6f, 0x06, 0x01, 0x07, 0xea, 0x06,
0xfe, 0x06, 0xe9, 0x06, 0xcf, 0x06, 0xc4, 0x06, 0x95, 0x06, 0x6f, 0x06, 0x82, 0x06, 0x99, 0x06,
0xcb, 0x06, 0x20, 0x06, 0xac, 0x06, 0xa8, 0x06, 0xb6, 0x06, 0xa8, 0x06, 0x8e, 0x06, 0x88, 0x06,
0x5a, 0x06, 0x32, 0x06, 0x37, 0x06, 0x37, 0x06, 0x22, 0x06, 0xfe, 0x05, 0xd8, 0x06, 0xc4, 0x06,
0xd6, 0x06, 0xc6, 0x06, 0xb0, 0x06, 0xa4, 0x06, 0x7a, 0x06, 0x4c, 0x06, 0x5b, 0x06, 0x68, 0x06,
0xb7, 0x06, 0xf8, 0x05, 0x47, 0x06, 0x48, 0x06, 0x50, 0x06, 0x45, 0x06, 0x30, 0x06, 0x2c, 0x06,
0x02, 0x06, 0xdb, 0x05, 0xe2, 0x05, 0xda, 0x05, 0xc5, 0x05, 0xad, 0x05, 0xb0, 0x06, 0x9a, 0x06,
0xa6, 0x06, 0x98, 0x06, 0x80, 0x06, 0x7c, 0x06, 0x55, 0x06, 0x28, 0x06, 0x33, 0x06, 0x26, 0x06,
0x1c, 0x06, 0xce, 0x05, 0xb3, 0x06, 0xb9, 0x06, 0xc7, 0x06, 0xbc, 0x06, 0xa2, 0x06, 0x9d, 0x06,
0x75, 0x06, 0x46, 0x06, 0x52, 0x06, 0x47, 0x06, 0x2f, 0x06, 0x18, 0x06, 0xfa, 0x06, 0xe3, 0x06,
0xf5, 0x06, 0xe9, 0x06, 0xd1, 0x06, 0xca, 0x06, 0x9b, 0x06, 0x6d, 0x06, 0x7c, 0x06, 0x6b, 0x06,
0x58, 0x06, 0x04, 0x06, 0xfc, 0x06, 0x18, 0x07, 0x2a, 0x07, 0x22, 0x07, 0x08, 0x07, 0x04, 0x07,
0xd3, 0x06, 0xa1, 0x06, 0xb1, 0x06, 0xa1, 0x06, 0x88, 0x06, 0x72, 0x06, 0x01, 0x07, 0xe9, 0x06,
0x00, 0x07, 0xfa, 0x06, 0xda, 0x06, 0xcf, 0x06, 0xa6, 0x06, 0x78, 0x06, 0x85, 0x06, 0x7b, 0x06,
0x61, 0x06, 0xf7, 0x05, 0x2e, 0x07, 0x0b, 0x07, 0x1c, 0x07, 0x18, 0x07, 0xf9, 0x06, 0xf0, 0x06,
0xc2, 0x06, 0x92, 0x06, 0xa0, 0x06, 0x95, 0x06, 0x7a, 0x06, 0x5a, 0x06, 0x76, 0x06, 0x65, 0x06,
0x7b, 0x06, 0x6b, 0x06, 0x61, 0x06, 0x4f, 0x06, 0x27, 0x06, 0xf8, 0x05, 0x08, 0x06, 0xf2, 0x05,
0xeb, 0x05, 0xd0, 0x05, 0xeb, 0x06, 0xdb, 0x06, 0xf0, 0x06, 0xe8, 0x06, 0xd3, 0x06, 0xca, 0x06,
0x96, 0x06, 0x64, 0x06, 0x73, 0x06, 0x63, 0x06, 0x4f, 0x06, 0x2a, 0x06, 0xba, 0x06, 0xae, 0x06,
0xc5, 0x06, 0xba, 0x06, 0xa8, 0x06, 0x9d, 0x06, 0x6b, 0x06, 0x3a, 0x06, 0x48, 0x06, 0x36, 0x06,
0x28, 0x06, 0xfc, 0x05, 0x40, 0x06, 0x07, 0x06, 0x1d, 0x06, 0x21, 0x06, 0x0d, 0x06, 0xef, 0x05,
0xc0, 0x05, 0xae, 0x05, 0xb0, 0x05, 0x8e, 0x05, 0x62, 0x05, 0xea, 0x05, 0x8c, 0x06, 0xb6, 0x05,
0xbd, 0x05, 0xb2, 0x05, 0x9e, 0x05, 0x95, 0x05, 0x99, 0x05, 0x6c, 0x05, 0x67, 0x05, 0x4c, 0x05,
0x46, 0x05, 0x8e, 0x05, 0x64, 0x06, 0xaa, 0x05, 0xad, 0x05, 0xb5, 0x05, 0xa3, 0x05, 0x91, 0x05,
0x42, 0x05, 0x2c, 0x05, 0x2c, 0x05, 0x27, 0x05, 0x21, 0x05, 0xa8, 0x05, 0x8e, 0x05, 0xc0, 0x05,
0xcc, 0x05, 0xc6, 0x05, 0xae, 0x05, 0xaa, 0x05, 0x98, 0x05, 0x68, 0x05, 0x6f, 0x05, 0x60, 0x05,
0x4d, 0x05, 0xf2, 0x04, 0xa8, 0x06, 0xdd, 0x04, 0x1c, 0x0c, 0x74, 0x0e, 0x1c, 0x0c, 0x74, 0x0e,
0x1c, 0x0c, 0x74, 0x0e, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x10, 0xdc, 0x19, 0x0c, 0x80, 0x38, 0x07,
0xcb, 0x13, 0x00, 0x00, 0xf2, 0xfe, 0x00, 0x00, 0x08, 0x70, 0x00, 0x40, 0x38, 0x67, 0x08, 0x70,
0xb9, 0x67, 0x08, 0x70, 0xe1, 0xf0, 0x00, 0x00, 0x08, 0x60, 0x00, 0x40, 0x38, 0x76, 0x08, 0x70,
0xd6, 0x72, 0x82, 0xfd, 0xe1, 0xf0, 0x00, 0x00, 0x3c, 0x10, 0x10, 0x00, 0xd1, 0xc1, 0x06, 0xe2,
0x08, 0xd0, 0x00, 0x40, 0x04, 0xc1, 0xc4, 0xe0, 0x82, 0x0a, 0xab, 0x00, 0x00, 0x00, 0x04, 0x21,
0xb9, 0xcd, 0x00, 0x70, 0x2b, 0x01, 0x00, 0x00, 0x34, 0xe1, 0xf2, 0xf6, 0x50, 0xc1, 0x2c, 0x10,
0x10, 0x00, 0xe1, 0xf0, 0x04, 0x70, 0xc6, 0x27, 0x82, 0x05, 0x08, 0x70, 0x0f, 0xc0, 0x2c, 0x70,
0xff, 0xff, 0x08, 0x60, 0x00, 0x40, 0xb9, 0x76, 0x3c, 0x71, 0xe1, 0xf0, 0x77, 0x41, 0x14, 0x71,
0x34, 0x41, 0xc6, 0x47, 0x82, 0x04, 0xb1, 0x32, 0x24, 0x24, 0xf2, 0xfb, 0xe1, 0xf0, 0x00, 0x00,
0xf7, 0x40, 0x04, 0x70, 0xc6, 0x74, 0x82, 0x07, 0x2f, 0x67, 0x07, 0x00, 0x26, 0x62, 0xa1, 0x36,
0x24, 0x71, 0xf2, 0xf9, 0xe1, 0xf0, 0x00, 0x00, 0x04, 0x70, 0xc6, 0x74, 0x82, 0x06, 0x2f, 0x67,
0x02, 0x00, 0x91, 0x36, 0x24, 0x71, 0xf2, 0xfa, 0xe1, 0xf0, 0x00, 0x00, 0x08, 0x60, 0x00, 0x30,
0x38, 0x76, 0x28, 0x00, 0xd4, 0x74, 0x92, 0xfd, 0xe1, 0xf0, 0x00, 0x00, 0x3c, 0x10, 0x10, 0x00,
0xd1, 0xc1, 0x06, 0xe2, 0x06, 0xd3, 0xcb, 0x05, 0x00, 0x00, 0x38, 0x70, 0x38, 0x07, 0x57, 0xe1,
0x26, 0xe7, 0xb1, 0xde, 0x50, 0xc1, 0x2c, 0x10, 0x10, 0x00, 0xe1, 0xf0, 0x77, 0x31, 0x04, 0x70,
0x14, 0x61, 0x34, 0x31, 0xc6, 0x36, 0x82, 0x05, 0x30, 0x52, 0x24, 0x24, 0x26, 0x75, 0xf2, 0xfa,
0x06, 0x27, 0xe1, 0xf0, 0x34, 0x18, 0xc1, 0xe1, 0x08, 0x60, 0x00, 0x30, 0x08, 0x50, 0xff, 0xcf,
0x0c, 0x70, 0x6c, 0x53, 0x0c, 0xf0, 0x94, 0xac, 0x0c, 0x40, 0x7c, 0x53, 0x26, 0xf5, 0x26, 0x76,
0x0c, 0xe0, 0x40, 0x07, 0x2c, 0x50, 0xa4, 0xac, 0x26, 0x46, 0x30, 0x27, 0x2f, 0x6e, 0x07, 0x00,
0x2f, 0x3f, 0x06, 0x00, 0xb1, 0x23, 0x38, 0x37, 0x10, 0x00, 0x26, 0x65, 0xb1, 0x36, 0xb1, 0x07,
0xb9, 0x07, 0x10, 0x00, 0x24, 0x74, 0xc6, 0x74, 0x92, 0xf1, 0x40, 0xe1, 0x24, 0x18, 0xe1, 0xf0,
0x34, 0x18, 0x08, 0x60, 0x00, 0x30, 0x08, 0x50, 0xff, 0xcf, 0xc1, 0xe1, 0x0c, 0x70, 0x6c, 0x53,
0x0c, 0xf0, 0x94, 0xac, 0x0c, 0x40, 0x7c, 0x53, 0x26, 0xf5, 0x26, 0x76, 0x0c, 0x30, 0x40, 0x07,
0x2c, 0x50, 0xa4, 0xac, 0x26, 0x46, 0x2f, 0x63, 0x07, 0x00, 0x2f, 0xef, 0x06, 0x00, 0x30, 0xee,
0xc4, 0x21, 0xb1, 0xe7, 0x92, 0x05, 0x26, 0x65, 0x30, 0x66, 0xb9, 0x67, 0x10, 0x00, 0x24, 0x74,
0xc6, 0x74, 0x92, 0xf2, 0x40, 0xe1, 0x24, 0x18, 0xe1, 0xf0, 0x00, 0x00, 0x3c, 0x10, 0x18, 0x00,
0xc1, 0xa1, 0x38, 0xb0, 0x3c, 0x07, 0xd9, 0xc1, 0x08, 0x00, 0x08, 0xc0, 0x00, 0x30, 0x06, 0xa2,
0x04, 0xd0, 0x2c, 0xc0, 0x00, 0x49, 0x18, 0x7b, 0x09, 0x00, 0xc6, 0xd7, 0x32, 0x18, 0x04, 0xe0,
0x18, 0x3b, 0x08, 0x00, 0xc6, 0xe3, 0x32, 0x11, 0x06, 0x2d, 0x9b, 0x38, 0x00, 0x00, 0x26, 0x2e,
0x06, 0x72, 0x57, 0x71, 0x26, 0x7c, 0x30, 0x77, 0x2f, 0x62, 0x02, 0x00, 0x26, 0x6a, 0x5c, 0x70,
0xff, 0x0f, 0xa1, 0x76, 0x24, 0xe1, 0xf2, 0xed, 0x24, 0xd1, 0xf2, 0xe6, 0x58, 0xc1, 0x08, 0x00,
0x40, 0xa1, 0x2c, 0x10, 0x18, 0x00, 0xe1, 0xf0, 0x3c, 0x10, 0x10, 0x00, 0xd1, 0xc1, 0x38, 0xe0,
0x3c, 0x07, 0x18, 0x3e, 0x0d, 0x00, 0x18, 0x2e, 0x08, 0x00, 0x0c, 0xd0, 0x40, 0x07, 0x9b, 0x38,
0x00, 0x00, 0x18, 0x7e, 0x0c, 0x00, 0x26, 0x27, 0xa9, 0x2d, 0x20, 0x00, 0x18, 0x3e, 0x0f, 0x00,
0x18, 0x2e, 0x08, 0x00, 0x9b, 0x38, 0x00, 0x00, 0x18, 0x7e, 0x0e, 0x00, 0x26, 0x27, 0xa9, 0x2d,
0x22, 0x00, 0x18, 0x3e, 0x11, 0x00, 0x18, 0x2e, 0x08, 0x00, 0x9b, 0x38, 0x00, 0x00, 0x18, 0x7e,
0x10, 0x00, 0x26, 0x27, 0xa9, 0x2d, 0x24, 0x00, 0x18, 0x3e, 0x13, 0x00, 0x18, 0x2e, 0x08, 0x00,
0x9b, 0x38, 0x00, 0x00, 0x18, 0x7e, 0x12, 0x00, 0x26, 0x27, 0xa9, 0x2d, 0x26, 0x00, 0x18, 0x2e,
0x08, 0x00, 0x18, 0x3e, 0x15, 0x00, 0x9b, 0x38, 0x00, 0x00, 0x18, 0x7e, 0x14, 0x00, 0x26, 0x27,
0xa9, 0x2d, 0x28, 0x00, 0x50, 0xc1, 0x2c, 0x10, 0x10, 0x00, 0xe1, 0xf0, 0x3c, 0x10, 0x14, 0x00,
0x08, 0x70, 0x00, 0x30, 0xd9, 0xc1, 0x04, 0x00, 0x2c, 0x70, 0x00, 0x01, 0xb9, 0x70, 0x38, 0x07,
0x0c, 0x70, 0xe0, 0x19, 0x0c, 0x60, 0x88, 0x13, 0xb9, 0x70, 0x3c, 0x07, 0xb1, 0xb1, 0x08, 0x70,
0x00, 0x40, 0xb9, 0x67, 0x74, 0x10, 0xcb, 0x05, 0x00, 0x00, 0x38, 0x70, 0x3c, 0x07, 0x38, 0xc0,
0x38, 0x07, 0x20, 0x37, 0x04, 0x20, 0x4b, 0x07, 0x00, 0x00, 0xb9, 0x2c, 0x08, 0x00, 0xab, 0x0f,
0x00, 0x00, 0x38, 0x70, 0x3c, 0x07, 0x06, 0xce, 0xa8, 0x67, 0x18, 0x00, 0x92, 0x04, 0x04, 0x61,
0xa9, 0x67, 0x18, 0x00, 0x08, 0xd0, 0x7d, 0x0e, 0x0c, 0xb0, 0x70, 0xc7, 0x04, 0xe0, 0x26, 0xbd,
0x38, 0x70, 0x38, 0x07, 0x30, 0x77, 0xd4, 0x71, 0x82, 0x13, 0x8b, 0x35, 0x00, 0x00, 0x0b, 0x1a,
0x00, 0x00, 0x06, 0x3e, 0x04, 0x21, 0x66, 0x3b, 0x4b, 0x06, 0x00, 0x00, 0x04, 0x61, 0x08, 0x70,
0x00, 0x40, 0x04, 0x20, 0xb9, 0x67, 0x70, 0x10, 0x06, 0x32, 0x4b, 0x06, 0x00, 0x00, 0x38, 0x70,
0x38, 0x07, 0x30, 0x77, 0xdc, 0x70, 0x00, 0x01, 0x82, 0xe4, 0x4b, 0x37, 0x00, 0x00, 0x0c, 0x30,
0x00, 0xc5, 0x06, 0xe2, 0x26, 0x3d, 0x66, 0x3e, 0x04, 0x21, 0x4b, 0x06, 0x00, 0x00, 0x04, 0x61,
0x08, 0x70, 0x00, 0x40, 0x04, 0x20, 0xb9, 0x67, 0x70, 0x10, 0x06, 0x32, 0x4b, 0x06, 0x00, 0x00,
0xf2, 0xd0, 0x00, 0x00, 0x3c, 0x10, 0x28, 0x00, 0xd9, 0x81, 0x08, 0x00, 0x06, 0x2b, 0x0c, 0x20,
0x00, 0x1a, 0x0c, 0x30, 0xff, 0x0f, 0x0c, 0x40, 0x80, 0x04, 0xd9, 0xc1, 0x18, 0x00, 0x6b, 0x04,
0x00, 0x00, 0x06, 0x2a, 0x0c, 0x20, 0x80, 0x1e, 0x04, 0x30, 0x0c, 0x40, 0x80, 0x04, 0x6b, 0x04,
0x00, 0x00, 0x04, 0x2a, 0x08, 0x80, 0x00, 0x30, 0xab, 0x01, 0x00, 0x00, 0x04, 0x90, 0x2c, 0x80,
0x00, 0x49, 0x38, 0xc0, 0x3c, 0x07, 0x28, 0x7c, 0x18, 0x00, 0xc6, 0x97, 0x32, 0x38, 0x04, 0x21,
0xab, 0x01, 0x00, 0x00, 0x38, 0xc0, 0x3c, 0x07, 0x04, 0xd0, 0x06, 0x6a, 0x0c, 0x60, 0x80, 0x1e,
0x06, 0x5b, 0x0c, 0x50, 0x00, 0x1a, 0x18, 0x7c, 0x09, 0x00, 0xc6, 0xd7, 0x32, 0x26, 0x04, 0xe0,
0x18, 0x3c, 0x08, 0x00, 0xc6, 0xe3, 0x32, 0x1f, 0x06, 0x2d, 0xb9, 0x51, 0x04, 0x00, 0xb1, 0x61,
0x9b, 0x38, 0x00, 0x00, 0x26, 0x2e, 0x06, 0x72, 0x30, 0x61, 0x38, 0x51, 0x04, 0x00, 0x57, 0x71,
0x26, 0x78, 0x26, 0x22, 0x30, 0x77, 0x2f, 0x46, 0x02, 0x00, 0x20, 0x34, 0x5c, 0x70, 0xff, 0x0f,
0xc6, 0x37, 0xb2, 0x02, 0xa1, 0x74, 0x26, 0x25, 0x20, 0x42, 0xc6, 0x47, 0xc2, 0x02, 0xa1, 0x72,
0x24, 0xe1, 0xf2, 0xdf, 0x24, 0xd1, 0xf2, 0xd8, 0x24, 0x91, 0xf2, 0xc4, 0x04, 0xd0, 0x0c, 0xa0,
0x80, 0x1e, 0x0c, 0xb0, 0x00, 0x1a, 0x18, 0x7c, 0x09, 0x00, 0xc6, 0xd7, 0x32, 0x17, 0x04, 0xe0,
0x18, 0x3c, 0x08, 0x00, 0xc6, 0xe3, 0x32, 0x10, 0x06, 0x2d, 0x9b, 0x38, 0x00, 0x00, 0x26, 0x2e,
0x26, 0x22, 0x2f, 0x7a, 0x02, 0x00, 0x26, 0x2b, 0x20, 0x57, 0x20, 0x62, 0x24, 0xe1, 0x3f, 0x66,
0x05, 0x00, 0xa1, 0x67, 0xf2, 0xee, 0x24, 0xd1, 0xf2, 0xe7, 0x58, 0xc1, 0x18, 0x00, 0x58, 0x81,
0x08, 0x00, 0x2c, 0x10, 0x28, 0x00, 0xe1, 0xf0, 0x3c, 0x10, 0x14, 0x00, 0xd9, 0xc1, 0x04, 0x00,
0x38, 0xe0, 0x3c, 0x07, 0xb1, 0xb1, 0x06, 0xc3, 0x18, 0x3e, 0x08, 0x00, 0x06, 0xb4, 0x06, 0xd2,
0x9b, 0x38, 0x00, 0x00, 0x26, 0x2c, 0xb1, 0x2b, 0x18, 0x7e, 0x0a, 0x00, 0xc6, 0xc7, 0xb2, 0x11,
0x18, 0x7e, 0x0b, 0x00, 0xc6, 0xd7, 0xa2, 0x0a, 0x18, 0x7e, 0x16, 0x00, 0xc6, 0xd7, 0x82, 0x06,
0x18, 0x7e, 0x17, 0x00, 0x04, 0x20, 0xc6, 0xd7, 0x92, 0x1e, 0x28, 0x2e, 0x1c, 0x00, 0xf2, 0x1b,
0x18, 0x6e, 0x04, 0x00, 0x2f, 0x76, 0x06, 0x00, 0x0c, 0x30, 0x40, 0x07, 0x26, 0x37, 0x34, 0x61,
0x04, 0x70, 0x14, 0x51, 0x2f, 0x47, 0x06, 0x00, 0xc6, 0x45, 0x82, 0x0c, 0x2f, 0x47, 0x07, 0x00,
0x26, 0x43, 0x28, 0x44, 0x1e, 0x00, 0x34, 0x71, 0xc6, 0x24, 0x92, 0xf5, 0x28, 0x2e, 0x1e, 0x00,
0xf2, 0x02, 0x04, 0x20, 0x58, 0xc1, 0x04, 0x00, 0x30, 0xb1, 0x2c, 0x10, 0x14, 0x00, 0xe1, 0xf0,
0x3c, 0x10, 0x10, 0x00, 0xd1, 0xc1, 0x06, 0xc2, 0x06, 0xe4, 0x04, 0x21, 0x06, 0xd3, 0x0b, 0x03,
0x00, 0x00, 0x08, 0x70, 0x00, 0x30, 0x2c, 0x70, 0x00, 0x40, 0x57, 0xc1, 0x2f, 0x27, 0x0c, 0x00,
0x30, 0x72, 0xc4, 0xe0, 0x0c, 0x60, 0xff, 0x03, 0x56, 0x67, 0x77, 0x75, 0x5c, 0x70, 0xff, 0x03,
0x82, 0x09, 0xc4, 0xd0, 0x82, 0x04, 0x26, 0x6e, 0x26, 0x7e, 0xf2, 0x11, 0x36, 0x7e, 0x36, 0x6e,
0xf2, 0x0e, 0xc4, 0xd0, 0x82, 0x07, 0xc6, 0x76, 0x02, 0x03, 0x24, 0x61, 0xf2, 0x0d, 0x24, 0x71,
0xf2, 0x06, 0xc6, 0x76, 0x02, 0x03, 0x34, 0x71, 0xf2, 0x02, 0x34, 0x61, 0xc4, 0x60, 0x02, 0x06,
0xcc, 0x60, 0xff, 0x03, 0x12, 0x06, 0x04, 0xe0, 0xf2, 0x07, 0x14, 0xe1, 0x04, 0x61, 0xf2, 0x04,
0x14, 0xe1, 0x0c, 0x60, 0xff, 0x03, 0xc4, 0x70, 0x02, 0x08, 0xcc, 0x70, 0xff, 0x03, 0x02, 0x07,
0x14, 0xe1, 0x0c, 0x70, 0xff, 0x03, 0xf2, 0x03, 0x14, 0xe1, 0x04, 0x71, 0x57, 0x75, 0x66, 0x76,
0xb1, 0x72, 0x04, 0x20, 0x0b, 0x03, 0x00, 0x00, 0x06, 0x2e, 0x50, 0xc1, 0x2c, 0x10, 0x10, 0x00,
0xe1, 0xf0, 0x00, 0x00, 0x3c, 0x10, 0x28, 0x00, 0xd9, 0xc1, 0x18, 0x00, 0x38, 0xe0, 0x3c, 0x07,
0xd9, 0x81, 0x08, 0x00, 0x06, 0xd2, 0x18, 0x7e, 0x05, 0x00, 0x18, 0x2e, 0x0b, 0x00, 0x18, 0x3e,
0x0a, 0x00, 0x26, 0x27, 0x9b, 0x38, 0x00, 0x00, 0x18, 0xae, 0x04, 0x00, 0x18, 0x3e, 0x08, 0x00,
0x26, 0x2a, 0xb9, 0x21, 0x04, 0x00, 0x18, 0x2e, 0x09, 0x00, 0x23, 0xdd, 0x9b, 0x38, 0x00, 0x00,
0x2f, 0x42, 0x02, 0x00, 0x06, 0x3d, 0x0c, 0x20, 0x00, 0x1a, 0x6b, 0x04, 0x00, 0x00, 0x18, 0x3e,
0x08, 0x00, 0x18, 0x2e, 0x09, 0x00, 0x9b, 0x38, 0x00, 0x00, 0x06, 0x42, 0x04, 0x30, 0x06, 0x2d,
0x0c, 0x20, 0x80, 0x1e, 0x2b, 0x05, 0x00, 0x00, 0x18, 0x3e, 0x08, 0x00, 0x18, 0x2e, 0x09, 0x00,
0x9b, 0x38, 0x00, 0x00, 0x06, 0x42, 0x04, 0x31, 0x06, 0x29, 0x0c, 0x20, 0xc0, 0x20, 0x08, 0xb0,
0x00, 0x30, 0x2b, 0x05, 0x00, 0x00, 0x0c, 0xc0, 0x82, 0x00, 0x2c, 0xb0, 0x00, 0x49, 0x04, 0x21,
0x04, 0x80, 0xab, 0x01, 0x00, 0x00, 0x06, 0xd8, 0x18, 0x7e, 0x09, 0x00, 0xc6, 0x87, 0x32, 0x46,
0x04, 0xa0, 0x18, 0x6e, 0x08, 0x00, 0xc6, 0xa6, 0x32, 0x3f, 0x06, 0x41, 0x06, 0x28, 0x06, 0x3a,
0x2b, 0x22, 0x00, 0x00, 0x86, 0x42, 0x82, 0x36, 0x30, 0x21, 0x06, 0x62, 0x57, 0x61, 0x26, 0x6b,
0x30, 0x66, 0x0c, 0x50, 0x80, 0x1e, 0x5c, 0x60, 0xff, 0x0f, 0x26, 0x52, 0x3f, 0x44, 0x06, 0x00,
0x90, 0x65, 0x82, 0x04, 0xcc, 0x40, 0x46, 0x00, 0x02, 0x24, 0x06, 0x69, 0x0c, 0x60, 0xc0, 0x20,
0x26, 0x62, 0x10, 0x36, 0xc4, 0x31, 0x0c, 0xf0, 0x00, 0x1a, 0x2f, 0x32, 0x02, 0x00, 0x92, 0x05,
0xc4, 0x40, 0x22, 0x0e, 0x91, 0x06, 0xf2, 0x0c, 0xc4, 0x40, 0x12, 0x0a, 0x04, 0x41, 0x91, 0x46,
0x2f, 0x43, 0x0f, 0x00, 0xa0, 0x44, 0x92, 0x04, 0x10, 0x45, 0x24, 0x41, 0x91, 0x45, 0x26, 0x3f,
0x20, 0x43, 0xf7, 0x40, 0xa1, 0x43, 0x10, 0x36, 0x6b, 0x26, 0x00, 0x00, 0xc4, 0x20, 0x32, 0x02,
0x24, 0xd1, 0x24, 0xa1, 0xf2, 0xbf, 0x24, 0x81, 0xf2, 0xb8, 0x38, 0x71, 0x04, 0x00, 0xc6, 0xd7,
0xb2, 0x03, 0xb4, 0xc1, 0x92, 0xad, 0x58, 0xc1, 0x18, 0x00, 0x58, 0x81, 0x08, 0x00, 0x2c, 0x10,
0x28, 0x00, 0xe1, 0xf0, 0x34, 0x14, 0x04, 0x21, 0xb1, 0xf1, 0x0b, 0x03, 0x00, 0x00, 0x08, 0x20,
0x00, 0x30, 0x08, 0x30, 0x06, 0x00, 0x2c, 0x30, 0x80, 0x01, 0x0c, 0x40, 0x00, 0x09, 0x2c, 0x20,
0x00, 0x40, 0xcb, 0x03, 0x00, 0x00, 0x04, 0x20, 0x0b, 0x03, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x02,
0x8b, 0x2b, 0x00, 0x00, 0x30, 0xf1, 0x24, 0x14, 0xe1, 0xf0, 0x00, 0x00, 0x34, 0x14, 0xb1, 0xf1,
0x0b, 0x08, 0x00, 0x00, 0x8b, 0x35, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x01, 0x6b, 0x0a, 0x00, 0x00,
0x04, 0x2a, 0xab, 0x01, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x23, 0xcb, 0x0c, 0x00, 0x00, 0x30, 0xf1,
0x04, 0x20, 0x24, 0x14, 0xe1, 0xf0, 0xc4, 0x30, 0x04, 0x40, 0x04, 0x50, 0x0c, 0x60, 0x20, 0x00,
0x52, 0x03, 0xa6, 0x42, 0x25, 0x50, 0xb4, 0x61, 0x02, 0x06, 0xa6, 0x44, 0x25, 0x55, 0xa6, 0x33,
0x42, 0xf9, 0xf2, 0xfa, 0x06, 0x24, 0x06, 0x35, 0xe1, 0xf0, 0x00, 0x00, 0x4a, 0xdc, 0xc5, 0x0d,
0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x0e, 0x15, 0x0e,
0x04, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
0xb9, 0x02, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x70, 0x00, 0x00,
0x00, 0x00, 0x96, 0x00, 0x60, 0x40, 0x14, 0x00, 0x54, 0xff, 0x0f, 0x00, 0x08, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x2c, 0x01, 0x38, 0x48, 0x10, 0x10, 0x01, 0x00, 0x08, 0x00,
0xc8, 0x00, 0xc8, 0x10, 0x61, 0x07, 0x05, 0x00, 0xff, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x64, 0xc0, 0x12, 0x00, 0x01, 0x00, 0x00, 0x00, 0x66, 0x02, 0x00, 0x00, 0x80, 0x0f, 0x80, 0x0f,
0x01, 0x00, 0x80, 0x00, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x16, 0x0e, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80,
0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x2c, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe2, 0x00, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x10, 0x08, 0x00, 0x10, 0x3f, 0x10, 0x3f, 0x64, 0x3c, 0x10, 0x00, 0x00, 0x00, 0x08, 0x82,
0x2c, 0x01, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xac, 0x0d, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x7f, 0xf0, 0x07,
0xdc, 0xc5, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x16, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x45, 0x06, 0x00,
0xb7, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0x84, 0x40, 0x00, 0x15, 0xf3, 0x88, 0x00, 0x00, 0xff, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x3f, 0x00, 0x88, 0xbf, 0x01, 0x20, 0x00, 0x00,
0x0c, 0x0d, 0x0e, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
0x1e, 0x21, 0x22, 0x23, 0x0a, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c,
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00, 0xff, 0x00, 0x20, 0x86, 0x00, 0x00, 0x00, 0x4e,
0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x46, 0x26, 0x20, 0x00,
0x4c, 0x29, 0x26, 0x03, 0x4a, 0x2b, 0x24, 0x05, 0x48, 0x2d, 0x22, 0x07, 0x48, 0x2d, 0x22, 0x07,
0x48, 0x2d, 0x22, 0x07, 0x48, 0x2e, 0x22, 0x08, 0x48, 0x2f, 0x22, 0x09, 0x4c, 0x2a, 0x29, 0x03,
0x46, 0x30, 0x20, 0x01, 0x4c, 0x2a, 0x26, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x4c, 0x26, 0x26, 0x00, 0x46, 0x27, 0x20, 0x01, 0xff, 0xf7, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x26, 0x07, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7b, 0xee, 0x09, 0x11, 0x76, 0xda, 0x09, 0x11, 0x71, 0xc6, 0x09, 0x11, 0x6b, 0xae, 0x09, 0x11,
0x64, 0x96, 0x09, 0x10, 0x5c, 0x72, 0x09, 0x10, 0x5d, 0x7a, 0x09, 0x10, 0x61, 0x86, 0x09, 0x10,
0x65, 0x96, 0x09, 0x0f, 0x66, 0x9a, 0x09, 0x0f, 0x6a, 0xaa, 0x09, 0x0f, 0x61, 0x86, 0x09, 0x0f,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0xbb, 0xee, 0x0a, 0x15, 0xbf, 0xfe, 0x0a, 0x15,
0xb6, 0xde, 0x0a, 0x15, 0xae, 0xbe, 0x0a, 0x15, 0xad, 0xb6, 0x0a, 0x14, 0x9d, 0x76, 0x0a, 0x14,
0x9a, 0x6e, 0x0a, 0x14, 0x9f, 0x7e, 0x0a, 0x14, 0xa5, 0x96, 0x0a, 0x13, 0xa6, 0x9e, 0x0a, 0x13,
0xa8, 0xa6, 0x0a, 0x13, 0x9e, 0x7e, 0x0a, 0x13, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0xa5, 0x96, 0x0a, 0x15, 0xab, 0xae, 0x0a, 0x15, 0xa9, 0xa6, 0x0a, 0x15, 0xa3, 0x8e, 0x0a, 0x15,
0xa3, 0x8e, 0x0a, 0x14, 0x99, 0x66, 0x0a, 0x14, 0x96, 0x5e, 0x0a, 0x14, 0x98, 0x66, 0x0a, 0x14,
0x9a, 0x6e, 0x0a, 0x13, 0x9b, 0x6e, 0x0a, 0x13, 0x96, 0x5e, 0x0a, 0x13, 0x8a, 0x2e, 0x0a, 0x13,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x3d, 0xf6, 0x18, 0x15, 0x3d, 0xf6, 0x18, 0x15,
0x3d, 0xf6, 0x18, 0x15, 0x3b, 0xee, 0x18, 0x15, 0x3d, 0xf6, 0x18, 0x14, 0x3a, 0xee, 0x18, 0x14,
0x3a, 0xea, 0x18, 0x14, 0x39, 0xe6, 0x18, 0x14, 0x3a, 0xea, 0x18, 0x13, 0x39, 0xe6, 0x18, 0x13,
0x39, 0xe6, 0x18, 0x13, 0x35, 0xd6, 0x18, 0x13, 0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a,
0x3f, 0xfe, 0x18, 0x15, 0x40, 0x02, 0x19, 0x15, 0x3f, 0x02, 0x19, 0x15, 0x3e, 0xfe, 0x18, 0x15,
0x40, 0x02, 0x19, 0x14, 0x3d, 0xf6, 0x18, 0x14, 0x3c, 0xf6, 0x18, 0x14, 0x3c, 0xf6, 0x18, 0x14,
0x3d, 0xf6, 0x18, 0x13, 0x3b, 0xee, 0x18, 0x13, 0x3b, 0xee, 0x18, 0x13, 0x37, 0xde, 0x18, 0x13,
0x00, 0x02, 0x18, 0x0a, 0x00, 0x02, 0x18, 0x0a, 0x35, 0xd6, 0xa8, 0x15, 0x36, 0xde, 0xa8, 0x15,
0x36, 0xde, 0xa8, 0x15, 0x35, 0xd6, 0xa8, 0x15, 0x37, 0xde, 0xa8, 0x14, 0x34, 0xd6, 0xa8, 0x14,
0x33, 0xce, 0xa8, 0x14, 0x32, 0xce, 0xa8, 0x14, 0x34, 0xd6, 0xa8, 0x13, 0x32, 0xca, 0xa8, 0x13,
0x32, 0xce, 0xa8, 0x13, 0x2e, 0xbe, 0xa8, 0x13, 0x00, 0x02, 0xa8, 0x0a, 0x00, 0x02, 0xa8, 0x0a,
0x2d, 0xb6, 0xa8, 0x14, 0x2c, 0xb6, 0xa8, 0x13, 0x2e, 0xbe, 0xa8, 0x13, 0x2c, 0xb6, 0xa8, 0x13,
0x2e, 0xba, 0xa8, 0x12, 0x2b, 0xae, 0xa8, 0x12, 0x2c, 0xb2, 0xa8, 0x12, 0x29, 0xaa, 0xa8, 0x12,
0x2a, 0xae, 0xa8, 0x11, 0x29, 0xaa, 0xa8, 0x11, 0x29, 0xaa, 0xa8, 0x11, 0x25, 0x96, 0xa8, 0x11,
0x00, 0x02, 0xa8, 0x0a, 0x00, 0x02, 0xa8, 0x0a, 0x2b, 0xae, 0xa8, 0x12, 0x2d, 0xb6, 0xa8, 0x11,
0x2d, 0xb6, 0xa8, 0x11, 0x2c, 0xb6, 0xa8, 0x11, 0x2e, 0xbe, 0xa8, 0x10, 0x2b, 0xae, 0xa8, 0x10,
0x2a, 0xae, 0xa8, 0x10, 0x2a, 0xae, 0xa8, 0x10, 0x2a, 0xae, 0xa8, 0x0f, 0x29, 0xa6, 0xa8, 0x0f,
0x28, 0xa6, 0xa8, 0x0f, 0x25, 0x9a, 0xa8, 0x0f, 0x00, 0x02, 0xa8, 0x0a, 0x00, 0x02, 0xa8, 0x0a,
0x2a, 0xae, 0x28, 0x10, 0x29, 0xaa, 0x28, 0x10, 0x29, 0xa6, 0x28, 0x10, 0x29, 0xa6, 0x28, 0x10,
0x2b, 0xae, 0x28, 0x0f, 0x29, 0xa6, 0x28, 0x0f, 0x29, 0xa6, 0x28, 0x0f, 0x29, 0xa6, 0x28, 0x0f,
0x28, 0xa6, 0x28, 0x0e, 0x26, 0x9e, 0x28, 0x0e, 0x26, 0x9e, 0x28, 0x0e, 0x23, 0x8e, 0x28, 0x0e,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x2c, 0xb6, 0x28, 0x10, 0x2b, 0xae, 0x28, 0x10,
0x2d, 0xb6, 0x28, 0x10, 0x2b, 0xae, 0x28, 0x10, 0x2d, 0xba, 0x28, 0x0f, 0x2a, 0xae, 0x28, 0x0f,
0x2a, 0xae, 0x28, 0x0f, 0x29, 0xa6, 0x28, 0x0f, 0x29, 0xa6, 0x28, 0x0e, 0x29, 0xa6, 0x28, 0x0e,
0x28, 0xa6, 0x28, 0x0e, 0x22, 0x8e, 0x28, 0x0e, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x2c, 0xb6, 0x28, 0x0f, 0x2b, 0xae, 0x28, 0x0f, 0x2c, 0xb6, 0x28, 0x0f, 0x2a, 0xae, 0x28, 0x0f,
0x2d, 0xb6, 0x28, 0x0e, 0x28, 0xa6, 0x28, 0x0e, 0x29, 0xa6, 0x28, 0x0e, 0x28, 0xa6, 0x28, 0x0e,
0x2a, 0xae, 0x28, 0x0d, 0x28, 0xa6, 0x28, 0x0d, 0x28, 0xa2, 0x28, 0x0d, 0x23, 0x8e, 0x28, 0x0d,
0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a, 0x2b, 0xae, 0x28, 0x0e, 0x2d, 0xb6, 0x28, 0x0e,
0x2c, 0xb6, 0x28, 0x0e, 0x2b, 0xae, 0x28, 0x0e, 0x2e, 0xbe, 0x28, 0x0d, 0x2b, 0xae, 0x28, 0x0d,
0x2a, 0xae, 0x28, 0x0d, 0x29, 0xaa, 0x28, 0x0d, 0x2a, 0xaa, 0x28, 0x0c, 0x28, 0xa6, 0x28, 0x0c,
0x28, 0xa6, 0x28, 0x0c, 0x24, 0x96, 0x28, 0x0c, 0x00, 0x02, 0x28, 0x0a, 0x00, 0x02, 0x28, 0x0a,
0x25, 0x9a, 0x38, 0x0b, 0x27, 0x9e, 0x38, 0x0a, 0x26, 0x9a, 0x38, 0x0b, 0x25, 0x96, 0x38, 0x0b,
0x26, 0x9e, 0x38, 0x0a, 0x25, 0x9a, 0x38, 0x0a, 0x23, 0x8e, 0x38, 0x0a, 0x24, 0x96, 0x38, 0x0a,
0x24, 0x92, 0x38, 0x09, 0x23, 0x8e, 0x38, 0x09, 0x23, 0x8e, 0x38, 0x09, 0x1e, 0x7e, 0x38, 0x09,
0x00, 0x02, 0x38, 0x0a, 0x00, 0x02, 0x38, 0x0a, 0x29, 0xa6, 0x48, 0x0c, 0x29, 0xa6, 0x48, 0x0b,
0x28, 0xa2, 0x48, 0x0c, 0x26, 0x9e, 0x48, 0x0c, 0x28, 0xa6, 0x48, 0x0b, 0x26, 0x9a, 0x48, 0x0b,
0x26, 0x9a, 0x48, 0x0b, 0x26, 0x9a, 0x48, 0x0b, 0x25, 0x9a, 0x48, 0x0a, 0x24, 0x96, 0x48, 0x0a,
0x24, 0x96, 0x48, 0x0a, 0x1f, 0x7e, 0x48, 0x0a, 0x00, 0x02, 0x48, 0x0a, 0x00, 0x02, 0x48, 0x0a,
0x28, 0xa6, 0x58, 0x0a, 0x29, 0xa6, 0x58, 0x0a, 0x29, 0xa6, 0x58, 0x0a, 0x27, 0x9e, 0x58, 0x0a,
0x29, 0xaa, 0x58, 0x0a, 0x26, 0x9a, 0x58, 0x0a, 0x26, 0x9e, 0x58, 0x0a, 0x25, 0x9a, 0x58, 0x0a,
0x26, 0x9a, 0x58, 0x09, 0x26, 0x9a, 0x58, 0x09, 0x25, 0x9a, 0x58, 0x09, 0x22, 0x8e, 0x58, 0x09,
0x00, 0x02, 0x58, 0x0a, 0x00, 0x02, 0x58, 0x0a, 0x2a, 0xaa, 0x68, 0x0c, 0x29, 0xa6, 0x68, 0x0d,
0x2a, 0xaa, 0x68, 0x0d, 0x28, 0xa6, 0x68, 0x0d, 0x2a, 0xae, 0x68, 0x0c, 0x26, 0x9e, 0x68, 0x0c,
0x26, 0x9e, 0x68, 0x0c, 0x26, 0x9e, 0x68, 0x0c, 0x27, 0x9e, 0x68, 0x0b, 0x26, 0x9a, 0x68, 0x0b,
0x26, 0x9a, 0x68, 0x0b, 0x20, 0x86, 0x68, 0x0b, 0x00, 0x02, 0x68, 0x0a, 0x00, 0x02, 0x68, 0x0a,
0x2e, 0xbe, 0x78, 0x0b, 0x2f, 0xc2, 0x78, 0x0c, 0x2f, 0xc2, 0x78, 0x0c, 0x2e, 0xba, 0x78, 0x0c,
0x30, 0xc6, 0x78, 0x0b, 0x2d, 0xb6, 0x78, 0x0b, 0x2d, 0xb6, 0x78, 0x0b, 0x2d, 0xb6, 0x78, 0x0b,
0x2e, 0xba, 0x78, 0x0a, 0x2c, 0xb6, 0x78, 0x0a, 0x2a, 0xae, 0x78, 0x0a, 0x28, 0xa2, 0x78, 0x0a,
0x00, 0x02, 0x78, 0x0a, 0x00, 0x02, 0x78, 0x0a, 0x22, 0x8a, 0x98, 0x12, 0x23, 0x8e, 0x98, 0x11,
0x22, 0x8a, 0x98, 0x11, 0x20, 0x82, 0x98, 0x11, 0x22, 0x8e, 0x98, 0x10, 0x1f, 0x7e, 0x98, 0x10,
0x1d, 0x7a, 0x98, 0x10, 0x1e, 0x7e, 0x98, 0x10, 0x1f, 0x7e, 0x98, 0x0f, 0x1f, 0x7e, 0x98, 0x0f,
0x1e, 0x7a, 0x98, 0x0f, 0x1e, 0x7e, 0x98, 0x0f, 0x00, 0x02, 0x98, 0x0a, 0x00, 0x02, 0x98, 0x0a,
0x1c, 0x72, 0x88, 0x0f, 0x18, 0x62, 0x88, 0x0e, 0x16, 0x5e, 0x88, 0x0e, 0x15, 0x56, 0x88, 0x0e,
0x18, 0x62, 0x88, 0x0d, 0x14, 0x56, 0x88, 0x0d, 0x14, 0x52, 0x88, 0x0d, 0x15, 0x56, 0x88, 0x0d,
0x15, 0x56, 0x88, 0x0c, 0x15, 0x56, 0x88, 0x0c, 0x15, 0x56, 0x88, 0x0c, 0x14, 0x52, 0x88, 0x0c,
0x00, 0x02, 0x88, 0x0a, 0x00, 0x02, 0x88, 0x0a, 0x15, 0x5a, 0x88, 0x0d, 0x13, 0x4e, 0x88, 0x0c,
0x12, 0x4a, 0x88, 0x0c, 0x11, 0x46, 0x88, 0x0c, 0x14, 0x52, 0x88, 0x0b, 0x10, 0x46, 0x88, 0x0b,
0x10, 0x42, 0x88, 0x0b, 0x10, 0x42, 0x88, 0x0b, 0x10, 0x42, 0x88, 0x0a, 0x10, 0x46, 0x88, 0x0a,
0x10, 0x46, 0x88, 0x0a, 0x11, 0x4a, 0x88, 0x0a, 0x00, 0x02, 0x88, 0x0a, 0x00, 0x02, 0x88, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0xbc, 0xf6, 0xfa, 0x15, 0x8a, 0x2e, 0xfa, 0x0e, 0x4f, 0x3e, 0xe9, 0x0a, 0x58, 0x62, 0xe9, 0x0a,
0x54, 0x56, 0xe9, 0x0a, 0x52, 0x4e, 0xe9, 0x0a, 0x55, 0x5a, 0xe9, 0x0a, 0x50, 0x46, 0xe9, 0x0a,
0x50, 0x42, 0xe9, 0x0a, 0x50, 0x46, 0xe9, 0x0a, 0x4e, 0x3e, 0xe9, 0x0a, 0x50, 0x42, 0xe9, 0x0a,
0x4c, 0x36, 0xe9, 0x0a, 0x42, 0x0e, 0xe9, 0x0a, 0x00, 0x02, 0xe8, 0x0a, 0x00, 0x02, 0xe8, 0x0a,
0x00, 0x02, 0x18, 0x0c, 0x00, 0x02, 0x18, 0x0c, 0x00, 0x02, 0x18, 0x0c, 0x00, 0x02, 0x18, 0x0c,
0x00, 0x02, 0x18, 0x0e, 0x00, 0x02, 0x18, 0x0c, 0x00, 0x02, 0x18, 0x0c, 0x00, 0x02, 0x28, 0x16,
0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16,
0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16,
0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16,
0x00, 0x02, 0xf8, 0x10, 0x00, 0x02, 0xf8, 0x12, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16,
0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16,
0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16,
0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x28, 0x16,
0x00, 0x02, 0x28, 0x16, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a, 0x00, 0x02, 0x08, 0x0a,
0x00, 0x40, 0xf0, 0x3b, 0x21, 0x40, 0xf0, 0x3b, 0x42, 0x40, 0xf0, 0x3b, 0x63, 0x40, 0xf0, 0x33,
0x84, 0x40, 0xf0, 0x33, 0xa5, 0x40, 0xf0, 0x33, 0xc6, 0xc0, 0xf1, 0x33, 0xe7, 0xc0, 0xf1, 0x33,
0x08, 0xc1, 0xf1, 0x33, 0x29, 0xc1, 0xf1, 0x33, 0x4a, 0xc1, 0xf1, 0x33, 0x6b, 0xc1, 0xf1, 0x33,
0x8c, 0xc1, 0xf1, 0x33, 0xad, 0xc1, 0xf1, 0x33, 0xce, 0xc1, 0xf1, 0x33, 0xef, 0xc1, 0xf1, 0x33,
0x10, 0xe2, 0xf1, 0x33, 0x31, 0x92, 0xf0, 0x3f, 0x52, 0x42, 0xf0, 0x3f, 0x73, 0x42, 0xf0, 0x3f,
0x94, 0xc2, 0xf1, 0x73, 0xb5, 0xc2, 0xf1, 0x33, 0x00, 0xc0, 0xf1, 0x33, 0x00, 0xc0, 0xf1, 0x33,
0x00, 0xc0, 0xf1, 0x33, 0x00, 0xc0, 0xf1, 0x33, 0x00, 0xc0, 0xf1, 0x33, 0x00, 0xc0, 0xf1, 0x33,
0x00, 0xc0, 0xf1, 0x33, 0x00, 0xc0, 0xf1, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x38, 0x30, 0x00, 0x34, 0x2f, 0x24, 0x1f, 0x00, 0x00, 0x00, 0x00,
0x34, 0x31, 0x24, 0x21, 0x36, 0x2c, 0x25, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x3f, 0xf0, 0x03, 0x00, 0x80, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00,
0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00,
0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00,
0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00,
0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00,
0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00,
0x30, 0x30, 0x30, 0x30, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x0e, 0x16, 0x0e,
0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x64, 0x00, 0x00, 0x00,
0x60, 0x21, 0x06, 0x00, 0x90, 0x00, 0x00, 0x00, 0x18, 0x20, 0x00, 0x00, 0x48, 0x9c, 0x00, 0x00,
0x00, 0x00, 0x96, 0x00, 0x30, 0x18, 0x12, 0x00, 0x14, 0xc8, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
0x14, 0x64, 0x08, 0x08, 0xe8, 0x03, 0x2c, 0x01, 0x14, 0x32, 0x10, 0x10, 0x20, 0x18, 0x07, 0x00,
0x64, 0x00, 0x64, 0x10, 0x63, 0x07, 0x02, 0x00, 0x32, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x64, 0xc0, 0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00,
0x30, 0x31, 0x83, 0x01, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0b, 0x17, 0x0f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80,
0x2c, 0x01, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x2c, 0x01, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
0xc8, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0xc8, 0x00, 0x01, 0x00, 0x40, 0xc2, 0x00, 0x00,
0x10, 0x00, 0x10, 0x00, 0xff, 0x00, 0x30, 0x00, 0xff, 0x05, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
0x10, 0x10, 0xa8, 0x00, 0x10, 0x3f, 0x10, 0x3f, 0x64, 0x3c, 0x10, 0x00, 0x00, 0x00, 0x04, 0x82,
0x00, 0x00, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x0f, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x20, 0x00, 0x02,
0x00, 0xf0, 0xff, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x0f,
0x17, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x07, 0x07, 0x00,
0xec, 0x53, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x51, 0x84, 0x40, 0x00, 0x15, 0x52, 0x80, 0x00, 0x14, 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x3f, 0x00, 0x88, 0xbf, 0x01, 0x20, 0x00, 0x00,
0x0c, 0x0d, 0x0e, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
0x1e, 0x21, 0x22, 0x23, 0x0a, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c,
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00, 0xff, 0x00, 0x30, 0x86, 0x00, 0x00, 0x00, 0x52,
0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x38, 0x28, 0x10, 0x00,
0x48, 0x38, 0x28, 0x10, 0x48, 0x29, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x29, 0x28, 0x01, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0x0f, 0x00, 0x00, 0x26, 0x07, 0x13, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x03, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x28, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x26, 0x9e, 0x08, 0x08, 0x27, 0x9e, 0x08, 0x08, 0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08,
0x29, 0xa6, 0x08, 0x08, 0x22, 0x8e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08, 0x26, 0x9e, 0x08, 0x08,
0x25, 0x96, 0x08, 0x08, 0x23, 0x8e, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08, 0x00, 0x02, 0x08, 0x08,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04, 0x00, 0x02, 0x08, 0x04,
0x00, 0xc0, 0xf1, 0x3f, 0x21, 0xc0, 0xf1, 0x3f, 0x42, 0xc0, 0xf1, 0x3f, 0x63, 0xc0, 0xf1, 0x3f,
0x84, 0xc0, 0xf1, 0x3f, 0xa5, 0xc0, 0xf1, 0x3f, 0xc6, 0xc0, 0xf1, 0x3f, 0xe7, 0xc0, 0xf1, 0x3f,
0x08, 0xc1, 0xf1, 0x3f, 0x29, 0xc1, 0xf1, 0x3f, 0x4a, 0xc1, 0xf1, 0x3f, 0x6b, 0xc1, 0xf1, 0x3f,
0x8c, 0xc1, 0xf1, 0x3f, 0xad, 0xc1, 0xf1, 0x3f, 0xce, 0xc1, 0xf1, 0x3f, 0xef, 0xc1, 0xf1, 0x3f,
0x10, 0xc2, 0xf1, 0x3f, 0x31, 0xc2, 0xf1, 0x3f, 0x52, 0xc2, 0xf1, 0x3f, 0x73, 0xc2, 0xf1, 0x3f,
0x94, 0xc2, 0xf1, 0x7f, 0xb5, 0xc2, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f,
0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f,
0x00, 0xc0, 0xf1, 0x3f, 0x00, 0xc0, 0xf1, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2e, 0x28, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x03, 0x00, 0x80, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x10, 0x10, 0x10, 0x10, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00,
0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0x04, 0x41, 0x10, 0x00, 0xcc, 0xcc, 0xcc, 0x0c,
0x43, 0x4d, 0x43, 0x53, 0x32, 0x54, 0x41, 0x47
};
#endif // __IST30XXC_CMCS_BIN_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
/*
* Copyright (C) 2010, Imagis Technology Co. Ltd. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __IST30XXC_MISC_H__
#define __IST30XXC_MISC_H__
#define NODE_FLAG_RAW (1)
#define NODE_FLAG_BASE (1 << 1)
#define NODE_FLAG_FILTER (1 << 2)
#define NODE_FLAG_DIFF (1 << 3)
#define NODE_FLAG_ALL (0xF)
#define NODE_FLAG_NO_CCP (1 << 7)
#define TS_RAW_ALL (0)
#define TS_RAW_SCREEN (1 << 0)
#define TS_RAW_KEY (1 << 1)
int ist30xx_check_valid_ch(struct ist30xx_data *data, int ch_tx, int ch_rx);
int ist30xx_parse_touch_node(struct ist30xx_data *data, u8 flag,
struct TSP_NODE_BUF *node);
int parse_tsp_node(struct ist30xx_data *data, u8 flag,
struct TSP_NODE_BUF *node, s16 *buf16, int mode);
int ist30xx_read_touch_node(struct ist30xx_data *data, u8 flag,
struct TSP_NODE_BUF *node);
int ist30xx_init_misc_sysfs(struct ist30xx_data *data);
#endif // __IST30XXC_MISC_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
/*
* Copyright (C) 2010, Imagis Technology Co. Ltd. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __IST30XXC_SEC_H__
#define __IST30XXC_SEC_H__
#define SEC_CMD_STR_LEN 32
#define SEC_CMD_RESULT_STR_LEN 2048
#define SEC_CMD_PARAM_NUM 8
struct sec_factory {
struct list_head cmd_list_head;
unsigned char cmd_state;
char cmd[SEC_CMD_STR_LEN];
int cmd_param[SEC_CMD_PARAM_NUM];
char *cmd_result;
int cmd_result_length;
struct mutex cmd_lock;
bool cmd_is_running;
};
#endif // __IST30XXC_SEC_H__

View file

@ -0,0 +1,494 @@
/*
* Copyright (C) 2010,Imagis Technology Co. Ltd. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <asm/unaligned.h>
#include <asm/io.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/machine.h>
#include "ist30xxc.h"
#include "ist30xxc_tracking.h"
/******************************************************************************
* Return value of Error
* EPERM : 1 (Operation not permitted)
* ENOENT : 2 (No such file or directory)
* EIO : 5 (I/O error)
* ENXIO : 6 (No such device or address)
* EINVAL : 22 (Invalid argument)
*****************************************************************************/
int ist30xx_cmd_gesture(struct i2c_client *client, int value)
{
int ret = -EIO;
if (value > 3)
return ret;
ret = ist30xx_write_cmd(client,
IST30XX_HIB_CMD, (eHCOM_GESTURE_EN << 16) | (value & 0xFFFF));
return ret;
}
int ist30xx_cmd_start_scan(struct ist30xx_data *data)
{
int ret = ist30xx_write_cmd(data->client, IST30XX_HIB_CMD,
(eHCOM_FW_START << 16) | (IST30XX_ENABLE & 0xFFFF));
ist30xx_tracking(TRACK_CMD_SCAN);
data->status.noise_mode = true;
return ret;
}
int ist30xx_cmd_calibrate(struct i2c_client *client)
{
int ret = ist30xx_write_cmd(client,
IST30XX_HIB_CMD, (eHCOM_RUN_CAL_AUTO << 16));
ist30xx_tracking(TRACK_CMD_CALIB);
tsp_info("%s\n", __func__);
return ret;
}
int ist30xx_cmd_check_calib(struct i2c_client *client)
{
int ret = ist30xx_write_cmd(client, IST30XX_HIB_CMD,
(eHCOM_RUN_CAL_PARAM << 16) | (IST30XX_ENABLE & 0xFFFF));
ist30xx_tracking(TRACK_CMD_CHECK_CALIB);
tsp_info("*** Check Calibration cmd ***\n");
return ret;
}
int ist30xx_cmd_hold(struct ist30xx_data *data, int enable)
{
int ret;
struct i2c_client *client = data->client;
if (!data->initialized && (data->status.update != 1))
return 0;
ret = ist30xx_write_cmd(client,
IST30XX_HIB_CMD, (eHCOM_FW_HOLD << 16) | (enable & 0xFFFF));
tsp_info("%s: FW HOLDE %s\n", __func__, enable ? "Enable" : "Disable");
if (enable)
ist30xx_tracking(TRACK_CMD_ENTER_REG);
else
ist30xx_tracking(TRACK_CMD_EXIT_REG);
return ret;
}
int ist30xx_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int msg_num, u8 *cmd_buf)
{
int ret = 0;
int idx = msg_num - 1;
int size = msgs[idx].len;
u8 *msg_buf = NULL;
u8 *pbuf = NULL;
int trans_size, max_size = 0;
if (msg_num == WRITE_CMD_MSG_LEN)
max_size = I2C_MAX_WRITE_SIZE;
else if (msg_num == READ_CMD_MSG_LEN)
max_size = I2C_MAX_READ_SIZE;
if (unlikely(max_size == 0)) {
tsp_err("%s() : transaction size(%d)\n", __func__, max_size);
return -EINVAL;
}
if (msg_num == WRITE_CMD_MSG_LEN) {
msg_buf = kmalloc(max_size + IST30XX_ADDR_LEN, GFP_KERNEL);
if (!msg_buf)
return -ENOMEM;
memcpy(msg_buf, cmd_buf, IST30XX_ADDR_LEN);
pbuf = msgs[idx].buf;
}
while (size > 0) {
trans_size = (size >= max_size ? max_size : size);
msgs[idx].len = trans_size;
if (msg_num == WRITE_CMD_MSG_LEN) {
memcpy(&msg_buf[IST30XX_ADDR_LEN], pbuf, trans_size);
msgs[idx].buf = msg_buf;
msgs[idx].len += IST30XX_ADDR_LEN;
}
ret = i2c_transfer(adap, msgs, msg_num);
if (unlikely(ret != msg_num)) {
tsp_err("%s() : i2c_transfer failed(%d), num=%d\n",
__func__, ret, msg_num);
break;
}
if (msg_num == WRITE_CMD_MSG_LEN)
pbuf += trans_size;
else
msgs[idx].buf += trans_size;
size -= trans_size;
}
if (msg_num == WRITE_CMD_MSG_LEN)
kfree(msg_buf);
return ret;
}
int ist30xx_read_buf(struct i2c_client *client, u32 cmd, u32 *buf, u16 len)
{
int ret, i;
u32 le_reg = cpu_to_be32(cmd);
struct i2c_msg msg[READ_CMD_MSG_LEN] = {
{
.addr = client->addr,
.flags = 0,
.len = IST30XX_ADDR_LEN,
.buf = (u8 *)&le_reg,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len * IST30XX_DATA_LEN,
.buf = (u8 *)buf,
},
};
ret = ist30xx_i2c_transfer(client->adapter, msg, READ_CMD_MSG_LEN, NULL);
if (unlikely(ret != READ_CMD_MSG_LEN))
return -EIO;
for (i = 0; i < len; i++)
buf[i] = cpu_to_be32(buf[i]);
return 0;
}
int ist30xx_write_buf(struct i2c_client *client, u32 cmd, u32 *buf, u16 len)
{
int i;
int ret;
struct i2c_msg msg;
u8 cmd_buf[IST30XX_ADDR_LEN];
u8 msg_buf[IST30XX_DATA_LEN * (len + 1)];
put_unaligned_be32(cmd, cmd_buf);
if (likely(len > 0)) {
for (i = 0; i < len; i++)
put_unaligned_be32(buf[i], msg_buf + (i * IST30XX_DATA_LEN));
} else {
/* then add dummy data(4byte) */
put_unaligned_be32(0, msg_buf);
len = 1;
}
msg.addr = client->addr;
msg.flags = 0;
msg.len = len * IST30XX_DATA_LEN;
msg.buf = msg_buf;
ret = ist30xx_i2c_transfer(client->adapter, &msg, WRITE_CMD_MSG_LEN,
cmd_buf);
if (unlikely(ret != WRITE_CMD_MSG_LEN))
return -EIO;
return 0;
}
int ist30xx_read_reg(struct i2c_client *client, u32 reg, u32 *buf)
{
int ret;
u32 le_reg = cpu_to_be32(reg);
struct i2c_msg msg[READ_CMD_MSG_LEN] = {
{
.addr = client->addr,
.flags = 0,
.len = IST30XX_ADDR_LEN,
.buf = (u8 *)&le_reg,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = IST30XX_DATA_LEN,
.buf = (u8 *)buf,
},
};
ret = i2c_transfer(client->adapter, msg, READ_CMD_MSG_LEN);
if (ret != READ_CMD_MSG_LEN) {
tsp_err("%s: i2c failed (%d), cmd: %x\n", __func__, ret, reg);
return -EIO;
}
*buf = cpu_to_be32(*buf);
return 0;
}
int ist30xx_read_cmd(struct ist30xx_data *data, u32 cmd, u32 *buf)
{
int ret;
ret = ist30xx_cmd_hold(data, 1);
if (unlikely(ret))
return ret;
ist30xx_read_reg(data->client, IST30XX_DA_ADDR(cmd), buf);
ret = ist30xx_cmd_hold(data, 0);
if (unlikely(ret)) {
ist30xx_reset(data, false);
return ret;
}
return ret;
}
int ist30xx_write_cmd(struct i2c_client *client, u32 cmd, u32 val)
{
int ret;
struct i2c_msg msg;
u8 msg_buf[IST30XX_ADDR_LEN + IST30XX_DATA_LEN];
put_unaligned_be32(cmd, msg_buf);
put_unaligned_be32(val, msg_buf + IST30XX_ADDR_LEN);
msg.addr = client->addr;
msg.flags = 0;
msg.len = IST30XX_ADDR_LEN + IST30XX_DATA_LEN;
msg.buf = msg_buf;
ret = i2c_transfer(client->adapter, &msg, WRITE_CMD_MSG_LEN);
if (ret != WRITE_CMD_MSG_LEN) {
tsp_err("%s: i2c failed (%d), cmd: %x(%x)\n", __func__, ret, cmd, val);
return -EIO;
}
msleep(40);
return 0;
}
int ist30xx_burst_read(struct i2c_client *client, u32 addr,
u32 *buf32, u16 len, bool bit_en)
{
int ret = 0;
int i;
u16 max_len = I2C_MAX_READ_SIZE / IST30XX_DATA_LEN;
u16 remain_len = len;
if (bit_en)
addr = IST30XX_BA_ADDR(addr);
for (i = 0; i < len; i += max_len) {
if (remain_len < max_len) max_len = remain_len;
ret = ist30xx_read_buf(client, addr, buf32, max_len);
if (unlikely(ret)) {
tsp_err("Burst fail, addr: %x\n", __func__, addr);
return ret;
}
addr += max_len * IST30XX_DATA_LEN;
buf32 += max_len;
remain_len -= max_len;
}
return 0;
}
int ist30xx_burst_write(struct i2c_client *client, u32 addr,
u32 *buf32, u16 len)
{
int ret = 0;
int i;
u16 max_len = I2C_MAX_WRITE_SIZE / IST30XX_DATA_LEN;
u16 remain_len = len;
addr = IST30XX_BA_ADDR(addr);
for (i = 0; i < len; i += max_len) {
if (remain_len < max_len) max_len = remain_len;
ret = ist30xx_write_buf(client, addr, buf32, max_len);
if (unlikely(ret)) {
tsp_err("Burst fail, addr: %x\n", __func__, addr);
return ret;
}
addr += max_len * IST30XX_DATA_LEN;
buf32 += max_len;
remain_len -= max_len;
}
return 0;
}
int ts_power_enable(struct ist30xx_data *data, int en)
{
struct regulator *regulator_avdd;
int retval = 0;
regulator_avdd = regulator_get(NULL, data->dt_data->regulator_avdd);
if (IS_ERR(regulator_avdd)) {
tsp_err("%s: Failed to get %s regulator.\n",
__func__, data->dt_data->regulator_avdd);
return PTR_ERR(regulator_avdd);
}
tsp_info("%s %s\n", __func__, (en) ? "on" : "off");
if (en) {
retval = regulator_enable(regulator_avdd);
if (retval) {
tsp_err("%s: Failed to enable avdd: %d\n", __func__, retval);
return retval;
}
} else {
if (regulator_is_enabled(regulator_avdd))
regulator_disable(regulator_avdd);
}
regulator_put(regulator_avdd);
return retval;
}
int ist30xx_power_on(struct ist30xx_data *data, bool download)
{
int rc = 0;
if (data->status.power != 1) {
tsp_info("%s()\n", __func__);
ist30xx_tracking(TRACK_PWR_ON);
/* VDD enable */
/* msleep(5);*/
/* VDDIO enable */
rc = ts_power_enable(data, 1);
if (download)
msleep(8);
else
msleep(60);
if (!rc) /*power is enabled successfully*/
data->status.power = 1;
}
return rc;
}
int ist30xx_power_off(struct ist30xx_data *data)
{
int rc = 0;
if (data->status.power != 0) {
tsp_info("%s()\n", __func__);
ist30xx_tracking(TRACK_PWR_OFF);
/* VDDIO disable */
/* msleep(5);*/
/* VDD disable */
rc = ts_power_enable(data, 0);
msleep(50);
if (!rc) /*power is disabled successfully*/
data->status.power = 0;
data->status.noise_mode = false;
}
return 0;
}
int ist30xx_reset(struct ist30xx_data *data, bool download)
{
tsp_info("%s()\n", __func__);
ist30xx_power_off(data);
msleep(10);
ist30xx_power_on(data, download);
return 0;
}
int ist30xx_internal_suspend(struct ist30xx_data *data)
{
#if IST30XX_GESTURE
data->suspend = true;
if (data->gesture) {
ist30xx_reset(data, false);
ist30xx_cmd_gesture(data->client, 3);
} else {
ist30xx_power_off(data);
}
#else
ist30xx_power_off(data);
#endif
return 0;
}
int ist30xx_internal_resume(struct ist30xx_data *data)
{
#if IST30XX_GESTURE
data->suspend = false;
if (data->gesture)
ist30xx_reset(data, false);
else
ist30xx_power_on(data, false);
#else
ist30xx_power_on(data, false);
#endif
return 0;
}
int ist30xx_init_system(struct ist30xx_data *data)
{
int ret;
// TODO : place additional code here.
ret = ist30xx_power_on(data, false);
if (ret) {
tsp_err("%s: ist30xx_init_system failed (%d)\n", __func__, ret);
return -EIO;
}
#if 0
ret = ist30xx_reset(data, false);
if (ret) {
tsp_err("%s: ist30xx_reset failed (%d)\n", __func__, ret);
return -EIO;
}
#endif
return 0;
}

View file

@ -0,0 +1,252 @@
/*
* Copyright (C) 2010,Imagis Technology Co. Ltd. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
#include "ist30xxc.h"
#include "ist30xxc_tracking.h"
IST30XX_RING_BUF TrackBuf;
IST30XX_RING_BUF *pTrackBuf;
bool tracking_initialize = false;
void ist30xx_tracking_init(void)
{
if (tracking_initialize)
return;
pTrackBuf = &TrackBuf;
pTrackBuf->RingBufCtr = 0;
pTrackBuf->RingBufInIdx = 0;
pTrackBuf->RingBufOutIdx = 0;
tracking_initialize = true;
}
void ist30xx_tracking_deinit(void)
{
}
static spinlock_t mr_lock = __SPIN_LOCK_UNLOCKED();
int ist30xx_get_track(u32 *track, int cnt)
{
int i;
u8 *buf = (u8 *)track;
unsigned long flags;
cnt *= sizeof(track[0]);
spin_lock_irqsave(&mr_lock, flags);
if (pTrackBuf->RingBufCtr < (u16)cnt) {
spin_unlock_irqrestore(&mr_lock, flags);
return IST30XX_RINGBUF_NOT_ENOUGH;
}
for (i = 0; i < cnt; i++) {
if (pTrackBuf->RingBufOutIdx == IST30XX_MAX_LOG_SIZE)
pTrackBuf->RingBufOutIdx = 0;
*buf++ = (u8)pTrackBuf->LogBuf[pTrackBuf->RingBufOutIdx++];
pTrackBuf->RingBufCtr--;
}
spin_unlock_irqrestore(&mr_lock, flags);
return IST30XX_RINGBUF_NO_ERR;
}
u32 ist30xx_get_track_cnt(void)
{
return pTrackBuf->RingBufCtr;
}
#if IST30XX_TRACKING_MODE
int ist30xx_put_track(u32 *track, int cnt)
{
int i;
u8 *buf = (u8 *)track;
unsigned long flags;
spin_lock_irqsave(&mr_lock, flags);
cnt *= sizeof(track[0]);
pTrackBuf->RingBufCtr += cnt;
if (pTrackBuf->RingBufCtr > IST30XX_MAX_LOG_SIZE) {
pTrackBuf->RingBufOutIdx +=
(pTrackBuf->RingBufCtr - IST30XX_MAX_LOG_SIZE);
if (pTrackBuf->RingBufOutIdx >= IST30XX_MAX_LOG_SIZE)
pTrackBuf->RingBufOutIdx -= IST30XX_MAX_LOG_SIZE;
pTrackBuf->RingBufCtr = IST30XX_MAX_LOG_SIZE;
}
for (i = 0; i < cnt; i++) {
if (pTrackBuf->RingBufInIdx == IST30XX_MAX_LOG_SIZE)
pTrackBuf->RingBufInIdx = 0;
pTrackBuf->LogBuf[pTrackBuf->RingBufInIdx++] = *buf++;
}
spin_unlock_irqrestore(&mr_lock, flags);
return IST30XX_RINGBUF_NO_ERR;
}
int ist30xx_put_track_ms(u32 ms)
{
ms &= 0x0000FFFF;
ms |= IST30XX_TRACKING_MAGIC;
return ist30xx_put_track(&ms, 1);
}
static struct timespec t_track;
int ist30xx_tracking(u32 status)
{
u32 ms;
if (!tracking_initialize)
ist30xx_tracking_init();
ktime_get_ts(&t_track);
ms = t_track.tv_sec * 1000 + t_track.tv_nsec / 1000000;
ist30xx_put_track_ms(ms);
ist30xx_put_track(&status, 1);
return 0;
}
#else
int ist30xx_put_track(u32 *track, int cnt)
{
return 0;
}
int ist30xx_put_track_ms(u32 ms)
{
return 0;
}
int ist30xx_tracking(u32 status)
{
return 0;
}
#endif // IST30XX_TRACKING_MODE
#define MAX_TRACKING_COUNT (1024)
/* sysfs: /sys/class/touch/tracking/track_frame */
ssize_t ist30xx_track_frame_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int i, buf_cnt = 0;
u32 track_cnt = MAX_TRACKING_COUNT;
u32 track;
char msg[10];
mutex_lock(&ist30xx_mutex);
buf[0] = '\0';
if (track_cnt > ist30xx_get_track_cnt())
track_cnt = ist30xx_get_track_cnt();
track_cnt /= sizeof(track);
tsp_verb("num: %d of %d\n", track_cnt, ist30xx_get_track_cnt());
for (i = 0; i < track_cnt; i++) {
ist30xx_get_track(&track, 1);
tsp_verb("%08X\n", track);
buf_cnt += sprintf(msg, "%08x", track);
strcat(buf, msg);
}
mutex_unlock(&ist30xx_mutex);
return buf_cnt;
}
/* sysfs: /sys/class/touch/tracking/track_cnt */
ssize_t ist30xx_track_cnt_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u32 val = (u32)ist30xx_get_track_cnt();
tsp_verb("tracking cnt: %d\n", val);
return sprintf(buf, "%08x", val);
}
static ssize_t ist30xx_track_enable_store(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct ist30xx_data *data = dev_get_drvdata(dev);
int val;
sscanf(buf, "%d", &val);
data->track_enable = (val ? true : false);
return count;
}
ssize_t ist30xx_track_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ist30xx_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s", data->track_enable ? "ENABLE" : "DISABLE");
}
/* sysfs */
static DEVICE_ATTR(track_frame, S_IRUGO, ist30xx_track_frame_show, NULL);
static DEVICE_ATTR(track_cnt, S_IRUGO, ist30xx_track_cnt_show, NULL);
static DEVICE_ATTR(track_enable, S_IWUSR | S_IWGRP | S_IRUGO, ist30xx_track_enable_show, ist30xx_track_enable_store);
static struct attribute *tracking_attributes[] = {
&dev_attr_track_frame.attr,
&dev_attr_track_cnt.attr,
&dev_attr_track_enable.attr,
NULL,
};
static struct attribute_group tracking_attr_group = {
.attrs = tracking_attributes,
};
extern struct class *ist30xx_class;
struct device *ist30xx_tracking_dev;
int ist30xx_init_tracking_sysfs(struct ist30xx_data *data)
{
/* /sys/class/touch/tracking */
ist30xx_tracking_dev = device_create(ist30xx_class, NULL, 0, NULL,
"tracking");
dev_set_drvdata(ist30xx_tracking_dev, data);
/* /sys/class/touch/tracking/... */
if (sysfs_create_group(&ist30xx_tracking_dev->kobj, &tracking_attr_group))
tsp_err("[ TSP ] Failed to create sysfs group(%s)!\n", "tracking");
ist30xx_tracking_init();
return 0;
}

View file

@ -0,0 +1,61 @@
#ifndef __IST30XXC_TRACKING_H__
#define __IST30XXC_TRACKING_H__
#define IST30XX_RINGBUF_NO_ERR (0)
#define IST30XX_RINGBUF_NOT_ENOUGH (1)
#define IST30XX_RINGBUF_EMPTY (2)
#define IST30XX_RINGBUF_FULL (3)
#define IST30XX_RINGBUF_TIMEOUT (4)
#define IST30XX_MAX_LOG_SIZE (4 * 100 * 1024) // 4bytes * 100Kbytes, Single touch: about 12minutes
#define TRACK_PWR_ON (0x1)
#define TRACK_PWR_OFF (0x2)
#define TRACK_PWR_RESET (0x3)
#define TRACK_INTR_ENABLE (0x4)
#define TRACK_INTR_DISABLE (0x5)
#define TRACK_CMD_RUN_DEVICE (0x10)
#define TRACK_CMD_SCAN (0x11)
#define TRACK_CMD_TACON (0x12)
#define TRACK_CMD_TADISCON (0x13)
#define TRACK_CMD_FWUPDATE (0x14)
#define TRACK_CMD_PRUPDATE (0x15)
#define TRACK_CMD_CALIB (0x16)
#define TRACK_CMD_CHECK_CALIB (0x17)
#define TRACK_CMD_CHKSUM (0x18)
#define TRACK_CMD_CHKSUM_ALL (0x19)
#define TRACK_CMD_ENTER_REG (0x1A)
#define TRACK_CMD_EXIT_REG (0x1B)
#define TRACK_CMD_CALL (0x1C)
#define TRACK_CMD_NOTCALL (0x1D)
#define TRACK_CMD_COVER (0x1E)
#define TRACK_CMD_NOTCOVER (0x1F)
#define TRACK_POS_FINGER (0x20)
#define TRACK_POS_KEY (0x30)
#define TRACK_POS_UNKNOWN (0x3F)
#define IST30XX_TRACKING_MAGIC (0x7750 << 16)
typedef struct _IST30XX_RINGBUF {
u32 RingBufCtr; // Number of characters in the ring buffer
u32 RingBufInIdx;
u32 RingBufOutIdx;
u8 LogBuf[IST30XX_MAX_LOG_SIZE]; // Ring buffer for status
} IST30XX_RING_BUF;
void ist30xx_tracking_init(void);
void ist30xx_tracking_deinit(void);
int ist30xx_get_track(u32 *track, int cnt);
int ist30xx_put_track(u32 *track, int cnt);
int ist30xx_put_track_ms(u32 ms);
u32 ist30xx_get_track_cnt(void);
int ist30xx_tracking(u32 status);
int ist30xx_init_tracking_sysfs(struct ist30xx_data *data);
#endif // __IST30XXC_TRACKING_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,102 @@
/*
* Copyright (C) 2010, Imagis Technology Co. Ltd. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __IST30XXC_UPDATE_H__
#define __IST30XXC_UPDATE_H__
// Flash size
#define IST30XX_FLASH_BASE_ADDR (0x0)
#if (IMAGIS_TSP_IC < IMAGIS_IST3038C)
#define IST30XX_FLASH_MAIN_SIZE (0x8000)
#define IST30XX_FLASH_INFO_SIZE (0x400)
#define IST30XX_FLASH_TOTAL_SIZE (0x8400)
#else
#define IST30XX_FLASH_MAIN_SIZE (0xFC00)
#define IST30XX_FLASH_INFO_SIZE (0x0)
#define IST30XX_FLASH_TOTAL_SIZE (0xFC00)
#endif
#define IST30XX_FLASH_PAGE_SIZE (0x400)
// Flash register
#define IST30XX_FLASH_BASE (0x40006000)
#define IST30XX_FLASH_MODE IST30XX_DA_ADDR(IST30XX_FLASH_BASE | 0x00)
#define IST30XX_FLASH_ADDR IST30XX_DA_ADDR(IST30XX_FLASH_BASE | 0x04)
#define IST30XX_FLASH_DIN IST30XX_DA_ADDR(IST30XX_FLASH_BASE | 0x08)
#define IST30XX_FLASH_DOUT IST30XX_DA_ADDR(IST30XX_FLASH_BASE | 0x0C)
#define IST30XX_FLASH_ISPEN IST30XX_DA_ADDR(IST30XX_FLASH_BASE | 0x10)
#define IST30XX_FLASH_AUTO_READ IST30XX_DA_ADDR(IST30XX_FLASH_BASE | 0x14)
#define IST30XX_FLASH_CRC IST30XX_DA_ADDR(IST30XX_FLASH_BASE | 0x18)
#define IST30XX_FLASH_TEST_MODE1 IST30XX_DA_ADDR(IST30XX_FLASH_BASE | 0x30)
#define IST30XX_FLASH_STATUS IST30XX_DA_ADDR(IST30XX_FLASH_BASE | 0x90)
// F/W update Info
#define IST30XX_FW_NAME "ist30xxc.fw"
#define IST30XX_BIN_NAME "ist30xxc.bin"
// Calibration
#define CALIB_WAIT_TIME (50) /* unit : 100msec */
#define CALIB_TO_GAP(n) ((n >> 16) & 0xFFF)
#define CALIB_TO_STATUS(n) ((n >> 12) & 0xF)
#define CALIB_TO_OS_VALUE(n) ((n >> 12) & 0xFFFF)
// Update func
#define MASK_UPDATE_INTERNAL (1)
#define MASK_UPDATE_FW (2)
#define MASK_UPDATE_SDCARD (3)
#define MASK_UPDATE_ERASE (4)
// Version flag
#define FLAG_MAIN (1)
#define FLAG_FW (2)
#define FLAG_CORE (3)
#define FLAG_TEST (4)
// TSP vendor (using gpio)
#define TSP_TYPE_UNKNOWN (0xF0)
#define TSP_TYPE_ALPS (0xF)
#define TSP_TYPE_EELY (0xE)
#define TSP_TYPE_TOP (0xD)
#define TSP_TYPE_MELFAS (0xC)
#define TSP_TYPE_ILJIN (0xB)
#define TSP_TYPE_SYNOPEX (0xA)
#define TSP_TYPE_SMAC (0x9)
#define TSP_TYPE_BOE_SLOC (0x8)
#define TSP_TYPE_TOVIS (0x7)
#define TSP_TYPE_ELK (0x6)
#define TSP_TYPE_OTHERS (0x5)
#define TSP_TYPE_CNI_GF1 (0x0)
#define TSP_TYPE_NO (0x10)
#define IST30XX_PARSE_TSPTYPE(n) ((n >> 1) & 0xF)
int ist30xx_read_chksum(struct i2c_client *client, u32 *chksum);
int ist30xx_read_chksum_all(struct i2c_client *client, u32 *chksum);
int ist30xx_get_update_info(struct ist30xx_data *data, const u8 *buf,
const u32 size);
int ist30xx_get_tsp_info(struct ist30xx_data *data);
void ist30xx_print_info(struct ist30xx_data *data);
u32 ist30xx_parse_ver(struct ist30xx_data *data, int flag, const u8 *buf);
int ist30xx_fw_update(struct ist30xx_data *data, const u8 *buf, int size);
int ist30xx_fw_recovery(struct ist30xx_data *data);
int ist30xx_auto_bin_update(struct ist30xx_data *data);
int ist30xx_calibrate(struct ist30xx_data *data, int wait_cnt);
int ist30xx_init_update_sysfs(struct ist30xx_data *data);
#endif // __IST30XXC_UPDATE_H__

View file

@ -0,0 +1,191 @@
/*
* iNexio serial touchscreen driver
*
* Copyright (c) 2008 Richard Lemon
* Based on the mtouch driver (c) Vojtech Pavlik and Dan Streetman
*
*/
/*
* 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.
*/
/*
* 2008/06/19 Richard Lemon <richard@codelemon.com>
* Copied mtouch.c and edited for iNexio protocol
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#define DRIVER_DESC "iNexio serial touchscreen driver"
MODULE_AUTHOR("Richard Lemon <richard@codelemon.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/*
* Definitions & global arrays.
*/
#define INEXIO_FORMAT_TOUCH_BIT 0x01
#define INEXIO_FORMAT_LENGTH 5
#define INEXIO_RESPONSE_BEGIN_BYTE 0x80
/* todo: check specs for max length of all responses */
#define INEXIO_MAX_LENGTH 16
#define INEXIO_MIN_XC 0
#define INEXIO_MAX_XC 0x3fff
#define INEXIO_MIN_YC 0
#define INEXIO_MAX_YC 0x3fff
#define INEXIO_GET_XC(data) (((data[1])<<7) | data[2])
#define INEXIO_GET_YC(data) (((data[3])<<7) | data[4])
#define INEXIO_GET_TOUCHED(data) (INEXIO_FORMAT_TOUCH_BIT & data[0])
/*
* Per-touchscreen data.
*/
struct inexio {
struct input_dev *dev;
struct serio *serio;
int idx;
unsigned char data[INEXIO_MAX_LENGTH];
char phys[32];
};
static void inexio_process_data(struct inexio *pinexio)
{
struct input_dev *dev = pinexio->dev;
if (INEXIO_FORMAT_LENGTH == ++pinexio->idx) {
input_report_abs(dev, ABS_X, INEXIO_GET_XC(pinexio->data));
input_report_abs(dev, ABS_Y, INEXIO_GET_YC(pinexio->data));
input_report_key(dev, BTN_TOUCH, INEXIO_GET_TOUCHED(pinexio->data));
input_sync(dev);
pinexio->idx = 0;
}
}
static irqreturn_t inexio_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct inexio* pinexio = serio_get_drvdata(serio);
pinexio->data[pinexio->idx] = data;
if (INEXIO_RESPONSE_BEGIN_BYTE&pinexio->data[0])
inexio_process_data(pinexio);
else
printk(KERN_DEBUG "inexio.c: unknown/unsynchronized data from device, byte %x\n",pinexio->data[0]);
return IRQ_HANDLED;
}
/*
* inexio_disconnect() is the opposite of inexio_connect()
*/
static void inexio_disconnect(struct serio *serio)
{
struct inexio* pinexio = serio_get_drvdata(serio);
input_get_device(pinexio->dev);
input_unregister_device(pinexio->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_put_device(pinexio->dev);
kfree(pinexio);
}
/*
* inexio_connect() is the routine that is called when someone adds a
* new serio device that supports iNexio protocol and registers it as
* an input device. This is usually accomplished using inputattach.
*/
static int inexio_connect(struct serio *serio, struct serio_driver *drv)
{
struct inexio *pinexio;
struct input_dev *input_dev;
int err;
pinexio = kzalloc(sizeof(struct inexio), GFP_KERNEL);
input_dev = input_allocate_device();
if (!pinexio || !input_dev) {
err = -ENOMEM;
goto fail1;
}
pinexio->serio = serio;
pinexio->dev = input_dev;
snprintf(pinexio->phys, sizeof(pinexio->phys), "%s/input0", serio->phys);
input_dev->name = "iNexio Serial TouchScreen";
input_dev->phys = pinexio->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_INEXIO;
input_dev->id.product = 0;
input_dev->id.version = 0x0001;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(pinexio->dev, ABS_X, INEXIO_MIN_XC, INEXIO_MAX_XC, 0, 0);
input_set_abs_params(pinexio->dev, ABS_Y, INEXIO_MIN_YC, INEXIO_MAX_YC, 0, 0);
serio_set_drvdata(serio, pinexio);
err = serio_open(serio, drv);
if (err)
goto fail2;
err = input_register_device(pinexio->dev);
if (err)
goto fail3;
return 0;
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(pinexio);
return err;
}
/*
* The serio driver structure.
*/
static struct serio_device_id inexio_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_INEXIO,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, inexio_serio_ids);
static struct serio_driver inexio_drv = {
.driver = {
.name = "inexio",
},
.description = DRIVER_DESC,
.id_table = inexio_serio_ids,
.interrupt = inexio_interrupt,
.connect = inexio_connect,
.disconnect = inexio_disconnect,
};
module_serio_driver(inexio_drv);

View file

@ -0,0 +1,655 @@
/*
* Intel MID Resistive Touch Screen Driver
*
* Copyright (C) 2008 Intel Corp
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* 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.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
* Ramesh Agarwal (ramesh.agarwal@intel.com)
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* TODO:
* review conversion of r/m/w sequences
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/param.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <asm/intel_scu_ipc.h>
#include <linux/device.h>
/* PMIC Interrupt registers */
#define PMIC_REG_ID1 0x00 /* PMIC ID1 register */
/* PMIC Interrupt registers */
#define PMIC_REG_INT 0x04 /* PMIC interrupt register */
#define PMIC_REG_MINT 0x05 /* PMIC interrupt mask register */
/* ADC Interrupt registers */
#define PMIC_REG_ADCINT 0x5F /* ADC interrupt register */
#define PMIC_REG_MADCINT 0x60 /* ADC interrupt mask register */
/* ADC Control registers */
#define PMIC_REG_ADCCNTL1 0x61 /* ADC control register */
/* ADC Channel Selection registers */
#define PMICADDR0 0xA4
#define END_OF_CHANNEL 0x1F
/* ADC Result register */
#define PMIC_REG_ADCSNS0H 0x64
/* ADC channels for touch screen */
#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */
#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */
#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */
#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */
/* Touch screen channel BIAS constants */
#define MRST_XBIAS 0x20
#define MRST_YBIAS 0x40
#define MRST_ZBIAS 0x80
/* Touch screen coordinates */
#define MRST_X_MIN 10
#define MRST_X_MAX 1024
#define MRST_X_FUZZ 5
#define MRST_Y_MIN 10
#define MRST_Y_MAX 1024
#define MRST_Y_FUZZ 5
#define MRST_PRESSURE_MIN 0
#define MRST_PRESSURE_NOMINAL 50
#define MRST_PRESSURE_MAX 100
#define WAIT_ADC_COMPLETION 10 /* msec */
/* PMIC ADC round robin delays */
#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */
/* PMIC Vendor Identifiers */
#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */
#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
/* Touch screen device structure */
struct mrstouch_dev {
struct device *dev; /* device associated with touch screen */
struct input_dev *input;
char phys[32];
u16 asr; /* Address selection register */
int irq;
unsigned int vendor; /* PMIC vendor */
unsigned int rev; /* PMIC revision */
int (*read_prepare)(struct mrstouch_dev *tsdev);
int (*read)(struct mrstouch_dev *tsdev, u16 *x, u16 *y, u16 *z);
int (*read_finish)(struct mrstouch_dev *tsdev);
};
/*************************** NEC and Maxim Interface ************************/
static int mrstouch_nec_adc_read_prepare(struct mrstouch_dev *tsdev)
{
return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0, 0x20);
}
/*
* Enables PENDET interrupt.
*/
static int mrstouch_nec_adc_read_finish(struct mrstouch_dev *tsdev)
{
int err;
err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x20, 0x20);
if (!err)
err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, 0, 0x05);
return err;
}
/*
* Reads PMIC ADC touch screen result
* Reads ADC storage registers for higher 7 and lower 3 bits and
* converts the two readings into a single value and turns off gain bit
*/
static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
{
int err;
u16 result;
u32 res;
result = PMIC_REG_ADCSNS0H + offset;
if (chan == MRST_TS_CHAN12)
result += 4;
err = intel_scu_ipc_ioread32(result, &res);
if (err)
return err;
/* Mash the bits up */
*vp = (res & 0xFF) << 3; /* Highest 7 bits */
*vp |= (res >> 8) & 0x07; /* Lower 3 bits */
*vp &= 0x3FF;
res >>= 16;
*vm = (res & 0xFF) << 3; /* Highest 7 bits */
*vm |= (res >> 8) & 0x07; /* Lower 3 bits */
*vm &= 0x3FF;
return 0;
}
/*
* Enables X, Y and Z bias values
* Enables YPYM for X channels and XPXM for Y channels
*/
static int mrstouch_ts_bias_set(uint offset, uint bias)
{
int count;
u16 chan, start;
u16 reg[4];
u8 data[4];
chan = PMICADDR0 + offset;
start = MRST_TS_CHAN10;
for (count = 0; count <= 3; count++) {
reg[count] = chan++;
data[count] = bias | (start + count);
}
return intel_scu_ipc_writev(reg, data, 4);
}
/* To read touch screen channel values */
static int mrstouch_nec_adc_read(struct mrstouch_dev *tsdev,
u16 *x, u16 *y, u16 *z)
{
int err;
u16 xm, ym, zm;
/* configure Y bias for X channels */
err = mrstouch_ts_bias_set(tsdev->asr, MRST_YBIAS);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/* read x+ and x- channels */
err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, x, &xm);
if (err)
goto ipc_error;
/* configure x bias for y channels */
err = mrstouch_ts_bias_set(tsdev->asr, MRST_XBIAS);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/* read y+ and y- channels */
err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, y, &ym);
if (err)
goto ipc_error;
/* configure z bias for x and y channels */
err = mrstouch_ts_bias_set(tsdev->asr, MRST_ZBIAS);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/* read z+ and z- channels */
err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, z, &zm);
if (err)
goto ipc_error;
return 0;
ipc_error:
dev_err(tsdev->dev, "ipc error during adc read\n");
return err;
}
/*************************** Freescale Interface ************************/
static int mrstouch_fs_adc_read_prepare(struct mrstouch_dev *tsdev)
{
int err, count;
u16 chan;
u16 reg[5];
u8 data[5];
/* Stop the ADC */
err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
if (err)
goto ipc_error;
chan = PMICADDR0 + tsdev->asr;
/* Set X BIAS */
for (count = 0; count <= 3; count++) {
reg[count] = chan++;
data[count] = 0x2A;
}
reg[count] = chan++; /* Dummy */
data[count] = 0;
err = intel_scu_ipc_writev(reg, data, 5);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/* Set Y BIAS */
for (count = 0; count <= 3; count++) {
reg[count] = chan++;
data[count] = 0x4A;
}
reg[count] = chan++; /* Dummy */
data[count] = 0;
err = intel_scu_ipc_writev(reg, data, 5);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/* Set Z BIAS */
err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
return 0;
ipc_error:
dev_err(tsdev->dev, "ipc error during %s\n", __func__);
return err;
}
static int mrstouch_fs_adc_read(struct mrstouch_dev *tsdev,
u16 *x, u16 *y, u16 *z)
{
int err;
u16 result;
u16 reg[4];
u8 data[4];
result = PMIC_REG_ADCSNS0H + tsdev->asr;
reg[0] = result + 4;
reg[1] = result + 5;
reg[2] = result + 16;
reg[3] = result + 17;
err = intel_scu_ipc_readv(reg, data, 4);
if (err)
goto ipc_error;
*x = data[0] << 3; /* Higher 7 bits */
*x |= data[1] & 0x7; /* Lower 3 bits */
*x &= 0x3FF;
*y = data[2] << 3; /* Higher 7 bits */
*y |= data[3] & 0x7; /* Lower 3 bits */
*y &= 0x3FF;
/* Read Z value */
reg[0] = result + 28;
reg[1] = result + 29;
err = intel_scu_ipc_readv(reg, data, 4);
if (err)
goto ipc_error;
*z = data[0] << 3; /* Higher 7 bits */
*z |= data[1] & 0x7; /* Lower 3 bits */
*z &= 0x3FF;
return 0;
ipc_error:
dev_err(tsdev->dev, "ipc error during %s\n", __func__);
return err;
}
static int mrstouch_fs_adc_read_finish(struct mrstouch_dev *tsdev)
{
int err, count;
u16 chan;
u16 reg[5];
u8 data[5];
/* Clear all TS channels */
chan = PMICADDR0 + tsdev->asr;
for (count = 0; count <= 4; count++) {
reg[count] = chan++;
data[count] = 0;
}
err = intel_scu_ipc_writev(reg, data, 5);
if (err)
goto ipc_error;
for (count = 0; count <= 4; count++) {
reg[count] = chan++;
data[count] = 0;
}
err = intel_scu_ipc_writev(reg, data, 5);
if (err)
goto ipc_error;
err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000);
if (err)
goto ipc_error;
/* Start ADC */
err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
if (err)
goto ipc_error;
return 0;
ipc_error:
dev_err(tsdev->dev, "ipc error during %s\n", __func__);
return err;
}
static void mrstouch_report_event(struct input_dev *input,
unsigned int x, unsigned int y, unsigned int z)
{
if (z > MRST_PRESSURE_NOMINAL) {
/* Pen touched, report button touch and coordinates */
input_report_key(input, BTN_TOUCH, 1);
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
} else {
input_report_key(input, BTN_TOUCH, 0);
}
input_report_abs(input, ABS_PRESSURE, z);
input_sync(input);
}
/* PENDET interrupt handler */
static irqreturn_t mrstouch_pendet_irq(int irq, void *dev_id)
{
struct mrstouch_dev *tsdev = dev_id;
u16 x, y, z;
/*
* Should we lower thread priority? Probably not, since we are
* not spinning but sleeping...
*/
if (tsdev->read_prepare(tsdev))
goto out;
do {
if (tsdev->read(tsdev, &x, &y, &z))
break;
mrstouch_report_event(tsdev->input, x, y, z);
} while (z > MRST_PRESSURE_NOMINAL);
tsdev->read_finish(tsdev);
out:
return IRQ_HANDLED;
}
/* Utility to read PMIC ID */
static int mrstouch_read_pmic_id(uint *vendor, uint *rev)
{
int err;
u8 r;
err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
if (err)
return err;
*vendor = r & 0x7;
*rev = (r >> 3) & 0x7;
return 0;
}
/*
* Parse ADC channels to find end of the channel configured by other ADC user
* NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
*/
static int mrstouch_chan_parse(struct mrstouch_dev *tsdev)
{
int found = 0;
int err, i;
u8 r8;
for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
err = intel_scu_ipc_ioread8(PMICADDR0 + i, &r8);
if (err)
return err;
if (r8 == END_OF_CHANNEL) {
found = i;
break;
}
}
if (tsdev->vendor == PMIC_VENDOR_FS) {
if (found > MRSTOUCH_MAX_CHANNELS - 18)
return -ENOSPC;
} else {
if (found > MRSTOUCH_MAX_CHANNELS - 4)
return -ENOSPC;
}
return found;
}
/*
* Writes touch screen channels to ADC address selection registers
*/
static int mrstouch_ts_chan_set(uint offset)
{
u16 chan;
int ret, count;
chan = PMICADDR0 + offset;
for (count = 0; count <= 3; count++) {
ret = intel_scu_ipc_iowrite8(chan++, MRST_TS_CHAN10 + count);
if (ret)
return ret;
}
return intel_scu_ipc_iowrite8(chan++, END_OF_CHANNEL);
}
/* Initialize ADC */
static int mrstouch_adc_init(struct mrstouch_dev *tsdev)
{
int err, start;
u8 ra, rm;
err = mrstouch_read_pmic_id(&tsdev->vendor, &tsdev->rev);
if (err) {
dev_err(tsdev->dev, "Unable to read PMIC id\n");
return err;
}
switch (tsdev->vendor) {
case PMIC_VENDOR_NEC:
case PMIC_VENDOR_MAXIM:
tsdev->read_prepare = mrstouch_nec_adc_read_prepare;
tsdev->read = mrstouch_nec_adc_read;
tsdev->read_finish = mrstouch_nec_adc_read_finish;
break;
case PMIC_VENDOR_FS:
tsdev->read_prepare = mrstouch_fs_adc_read_prepare;
tsdev->read = mrstouch_fs_adc_read;
tsdev->read_finish = mrstouch_fs_adc_read_finish;
break;
default:
dev_err(tsdev->dev,
"Unsupported touchscreen: %d\n", tsdev->vendor);
return -ENXIO;
}
start = mrstouch_chan_parse(tsdev);
if (start < 0) {
dev_err(tsdev->dev, "Unable to parse channels\n");
return start;
}
tsdev->asr = start;
/*
* ADC power on, start, enable PENDET and set loop delay
* ADC loop delay is set to 4.5 ms approximately
* Loop delay more than this results in jitter in adc readings
* Setting loop delay to 0 (continuous loop) in MAXIM stops PENDET
* interrupt generation sometimes.
*/
if (tsdev->vendor == PMIC_VENDOR_FS) {
ra = 0xE0 | ADC_LOOP_DELAY0;
rm = 0x5;
} else {
/* NEC and MAXIm not consistent with loop delay 0 */
ra = 0xE0 | ADC_LOOP_DELAY1;
rm = 0x0;
/* configure touch screen channels */
err = mrstouch_ts_chan_set(tsdev->asr);
if (err)
return err;
}
err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
if (err)
return err;
err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
if (err)
return err;
return 0;
}
/* Probe function for touch screen driver */
static int mrstouch_probe(struct platform_device *pdev)
{
struct mrstouch_dev *tsdev;
struct input_dev *input;
int err;
int irq;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no interrupt assigned\n");
return -EINVAL;
}
tsdev = devm_kzalloc(&pdev->dev, sizeof(struct mrstouch_dev),
GFP_KERNEL);
if (!tsdev) {
dev_err(&pdev->dev, "unable to allocate memory\n");
return -ENOMEM;
}
input = devm_input_allocate_device(&pdev->dev);
if (!input) {
dev_err(&pdev->dev, "unable to allocate input device\n");
return -ENOMEM;
}
tsdev->dev = &pdev->dev;
tsdev->input = input;
tsdev->irq = irq;
snprintf(tsdev->phys, sizeof(tsdev->phys),
"%s/input0", dev_name(tsdev->dev));
err = mrstouch_adc_init(tsdev);
if (err) {
dev_err(&pdev->dev, "ADC initialization failed\n");
return err;
}
input->name = "mrst_touchscreen";
input->phys = tsdev->phys;
input->dev.parent = tsdev->dev;
input->id.vendor = tsdev->vendor;
input->id.version = tsdev->rev;
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(tsdev->input, ABS_X,
MRST_X_MIN, MRST_X_MAX, MRST_X_FUZZ, 0);
input_set_abs_params(tsdev->input, ABS_Y,
MRST_Y_MIN, MRST_Y_MAX, MRST_Y_FUZZ, 0);
input_set_abs_params(tsdev->input, ABS_PRESSURE,
MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
err = devm_request_threaded_irq(&pdev->dev, tsdev->irq, NULL,
mrstouch_pendet_irq, IRQF_ONESHOT,
"mrstouch", tsdev);
if (err) {
dev_err(tsdev->dev, "unable to allocate irq\n");
return err;
}
err = input_register_device(tsdev->input);
if (err) {
dev_err(tsdev->dev, "unable to register input device\n");
return err;
}
return 0;
}
static struct platform_driver mrstouch_driver = {
.driver = {
.name = "pmic_touch",
.owner = THIS_MODULE,
},
.probe = mrstouch_probe,
};
module_platform_driver(mrstouch_driver);
MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,166 @@
/*
* 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.
*
* h3600 atmel micro companion support, touchscreen subdevice
* Author : Alessandro Gardich <gremlin@gremlin.it>
* Author : Dmitry Artamonow <mad_soft@inbox.ru>
* Author : Linus Walleij <linus.walleij@linaro.org>
*
*/
#include <asm/byteorder.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mfd/ipaq-micro.h>
struct touchscreen_data {
struct input_dev *input;
struct ipaq_micro *micro;
};
static void micro_ts_receive(void *data, int len, unsigned char *msg)
{
struct touchscreen_data *ts = data;
if (len == 4) {
input_report_abs(ts->input, ABS_X,
be16_to_cpup((__be16 *) &msg[2]));
input_report_abs(ts->input, ABS_Y,
be16_to_cpup((__be16 *) &msg[0]));
input_report_key(ts->input, BTN_TOUCH, 1);
input_sync(ts->input);
} else if (len == 0) {
input_report_abs(ts->input, ABS_X, 0);
input_report_abs(ts->input, ABS_Y, 0);
input_report_key(ts->input, BTN_TOUCH, 0);
input_sync(ts->input);
}
}
static void micro_ts_toggle_receive(struct touchscreen_data *ts, bool enable)
{
struct ipaq_micro *micro = ts->micro;
spin_lock_irq(&micro->lock);
if (enable) {
micro->ts = micro_ts_receive;
micro->ts_data = ts;
} else {
micro->ts = NULL;
micro->ts_data = NULL;
}
spin_unlock_irq(&ts->micro->lock);
}
static int micro_ts_open(struct input_dev *input)
{
struct touchscreen_data *ts = input_get_drvdata(input);
micro_ts_toggle_receive(ts, true);
return 0;
}
static void micro_ts_close(struct input_dev *input)
{
struct touchscreen_data *ts = input_get_drvdata(input);
micro_ts_toggle_receive(ts, false);
}
static int micro_ts_probe(struct platform_device *pdev)
{
struct ipaq_micro *micro = dev_get_drvdata(pdev->dev.parent);
struct touchscreen_data *ts;
int error;
ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
ts->micro = micro;
ts->input = devm_input_allocate_device(&pdev->dev);
if (!ts->input) {
dev_err(&pdev->dev, "failed to allocate input device\n");
return -ENOMEM;
}
ts->input->name = "ipaq micro ts";
ts->input->open = micro_ts_open;
ts->input->close = micro_ts_close;
input_set_drvdata(ts->input, ts);
input_set_capability(ts->input, EV_KEY, BTN_TOUCH);
input_set_capability(ts->input, EV_ABS, ABS_X);
input_set_capability(ts->input, EV_ABS, ABS_Y);
input_set_abs_params(ts->input, ABS_X, 0, 1023, 0, 0);
input_set_abs_params(ts->input, ABS_Y, 0, 1023, 0, 0);
error = input_register_device(ts->input);
if (error) {
dev_err(&pdev->dev, "error registering touch input\n");
return error;
}
platform_set_drvdata(pdev, ts);
dev_info(&pdev->dev, "iPAQ micro touchscreen\n");
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int micro_ts_suspend(struct device *dev)
{
struct touchscreen_data *ts = dev_get_drvdata(dev);
micro_ts_toggle_receive(ts, false);
return 0;
}
static int micro_ts_resume(struct device *dev)
{
struct touchscreen_data *ts = dev_get_drvdata(dev);
struct input_dev *input = ts->input;
mutex_lock(&input->mutex);
if (input->users)
micro_ts_toggle_receive(ts, true);
mutex_unlock(&input->mutex);
return 0;
}
#endif
static const struct dev_pm_ops micro_ts_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(micro_ts_suspend, micro_ts_resume)
};
static struct platform_driver micro_ts_device_driver = {
.driver = {
.name = "ipaq-micro-ts",
.pm = &micro_ts_dev_pm_ops,
},
.probe = micro_ts_probe,
};
module_platform_driver(micro_ts_device_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("driver for iPAQ Atmel micro touchscreen");
MODULE_ALIAS("platform:ipaq-micro-ts");

View file

@ -0,0 +1,154 @@
/*
* drivers/input/touchscreen/jornada720_ts.c
*
* Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
*
* Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
* based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org>
*
* 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.
*
* HP Jornada 710/720/729 Touchscreen Driver
*/
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <mach/jornada720.h>
#include <mach/irqs.h>
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
MODULE_LICENSE("GPL v2");
struct jornada_ts {
struct input_dev *dev;
int x_data[4]; /* X sample values */
int y_data[4]; /* Y sample values */
};
static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts)
{
/* 3 low word X samples */
jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY);
jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY);
jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY);
/* 3 low word Y samples */
jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY);
jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY);
jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY);
/* combined x samples bits */
jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY);
/* combined y samples bits */
jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY);
}
static int jornada720_ts_average(int coords[4])
{
int coord, high_bits = coords[3];
coord = coords[0] | ((high_bits & 0x03) << 8);
coord += coords[1] | ((high_bits & 0x0c) << 6);
coord += coords[2] | ((high_bits & 0x30) << 4);
return coord / 3;
}
static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
struct input_dev *input = jornada_ts->dev;
int x, y;
/* If GPIO_GPIO9 is set to high then report pen up */
if (GPLR & GPIO_GPIO(9)) {
input_report_key(input, BTN_TOUCH, 0);
input_sync(input);
} else {
jornada_ssp_start();
/* proper reply to request is always TXDUMMY */
if (jornada_ssp_inout(GETTOUCHSAMPLES) == TXDUMMY) {
jornada720_ts_collect_data(jornada_ts);
x = jornada720_ts_average(jornada_ts->x_data);
y = jornada720_ts_average(jornada_ts->y_data);
input_report_key(input, BTN_TOUCH, 1);
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
input_sync(input);
}
jornada_ssp_end();
}
return IRQ_HANDLED;
}
static int jornada720_ts_probe(struct platform_device *pdev)
{
struct jornada_ts *jornada_ts;
struct input_dev *input_dev;
int error;
jornada_ts = devm_kzalloc(&pdev->dev, sizeof(*jornada_ts), GFP_KERNEL);
if (!jornada_ts)
return -ENOMEM;
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev)
return -ENOMEM;
platform_set_drvdata(pdev, jornada_ts);
jornada_ts->dev = input_dev;
input_dev->name = "HP Jornada 7xx Touchscreen";
input_dev->phys = "jornadats/input0";
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
error = devm_request_irq(&pdev->dev, IRQ_GPIO9,
jornada720_ts_interrupt,
IRQF_TRIGGER_RISING,
"HP7XX Touchscreen driver", pdev);
if (error) {
dev_err(&pdev->dev, "HP7XX TS : Unable to acquire irq!\n");
return error;
}
error = input_register_device(jornada_ts->dev);
if (error)
return error;
return 0;
}
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:jornada_ts");
static struct platform_driver jornada720_ts_driver = {
.probe = jornada720_ts_probe,
.driver = {
.name = "jornada_ts",
.owner = THIS_MODULE,
},
};
module_platform_driver(jornada720_ts_driver);

View file

@ -0,0 +1,409 @@
/*
* LPC32xx built-in touchscreen driver
*
* Copyright (C) 2010 NXP Semiconductors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*/
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/of.h>
/*
* Touchscreen controller register offsets
*/
#define LPC32XX_TSC_STAT 0x00
#define LPC32XX_TSC_SEL 0x04
#define LPC32XX_TSC_CON 0x08
#define LPC32XX_TSC_FIFO 0x0C
#define LPC32XX_TSC_DTR 0x10
#define LPC32XX_TSC_RTR 0x14
#define LPC32XX_TSC_UTR 0x18
#define LPC32XX_TSC_TTR 0x1C
#define LPC32XX_TSC_DXP 0x20
#define LPC32XX_TSC_MIN_X 0x24
#define LPC32XX_TSC_MAX_X 0x28
#define LPC32XX_TSC_MIN_Y 0x2C
#define LPC32XX_TSC_MAX_Y 0x30
#define LPC32XX_TSC_AUX_UTR 0x34
#define LPC32XX_TSC_AUX_MIN 0x38
#define LPC32XX_TSC_AUX_MAX 0x3C
#define LPC32XX_TSC_STAT_FIFO_OVRRN (1 << 8)
#define LPC32XX_TSC_STAT_FIFO_EMPTY (1 << 7)
#define LPC32XX_TSC_SEL_DEFVAL 0x0284
#define LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 (0x1 << 11)
#define LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(s) ((10 - (s)) << 7)
#define LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(s) ((10 - (s)) << 4)
#define LPC32XX_TSC_ADCCON_POWER_UP (1 << 2)
#define LPC32XX_TSC_ADCCON_AUTO_EN (1 << 0)
#define LPC32XX_TSC_FIFO_TS_P_LEVEL (1 << 31)
#define LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(x) (((x) & 0x03FF0000) >> 16)
#define LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(y) ((y) & 0x000003FF)
#define LPC32XX_TSC_ADCDAT_VALUE_MASK 0x000003FF
#define LPC32XX_TSC_MIN_XY_VAL 0x0
#define LPC32XX_TSC_MAX_XY_VAL 0x3FF
#define MOD_NAME "ts-lpc32xx"
#define tsc_readl(dev, reg) \
__raw_readl((dev)->tsc_base + (reg))
#define tsc_writel(dev, reg, val) \
__raw_writel((val), (dev)->tsc_base + (reg))
struct lpc32xx_tsc {
struct input_dev *dev;
void __iomem *tsc_base;
int irq;
struct clk *clk;
};
static void lpc32xx_fifo_clear(struct lpc32xx_tsc *tsc)
{
while (!(tsc_readl(tsc, LPC32XX_TSC_STAT) &
LPC32XX_TSC_STAT_FIFO_EMPTY))
tsc_readl(tsc, LPC32XX_TSC_FIFO);
}
static irqreturn_t lpc32xx_ts_interrupt(int irq, void *dev_id)
{
u32 tmp, rv[4], xs[4], ys[4];
int idx;
struct lpc32xx_tsc *tsc = dev_id;
struct input_dev *input = tsc->dev;
tmp = tsc_readl(tsc, LPC32XX_TSC_STAT);
if (tmp & LPC32XX_TSC_STAT_FIFO_OVRRN) {
/* FIFO overflow - throw away samples */
lpc32xx_fifo_clear(tsc);
return IRQ_HANDLED;
}
/*
* Gather and normalize 4 samples. Pen-up events may have less
* than 4 samples, but its ok to pop 4 and let the last sample
* pen status check drop the samples.
*/
idx = 0;
while (idx < 4 &&
!(tsc_readl(tsc, LPC32XX_TSC_STAT) &
LPC32XX_TSC_STAT_FIFO_EMPTY)) {
tmp = tsc_readl(tsc, LPC32XX_TSC_FIFO);
xs[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(tmp);
ys[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(tmp);
rv[idx] = tmp;
idx++;
}
/* Data is only valid if pen is still down in last sample */
if (!(rv[3] & LPC32XX_TSC_FIFO_TS_P_LEVEL) && idx == 4) {
/* Use average of 2nd and 3rd sample for position */
input_report_abs(input, ABS_X, (xs[1] + xs[2]) / 2);
input_report_abs(input, ABS_Y, (ys[1] + ys[2]) / 2);
input_report_key(input, BTN_TOUCH, 1);
} else {
input_report_key(input, BTN_TOUCH, 0);
}
input_sync(input);
return IRQ_HANDLED;
}
static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc)
{
/* Disable auto mode */
tsc_writel(tsc, LPC32XX_TSC_CON,
tsc_readl(tsc, LPC32XX_TSC_CON) &
~LPC32XX_TSC_ADCCON_AUTO_EN);
clk_disable(tsc->clk);
}
static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
{
u32 tmp;
clk_enable(tsc->clk);
tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP;
/* Set the TSC FIFO depth to 4 samples @ 10-bits per sample (max) */
tmp = LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 |
LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(10) |
LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(10);
tsc_writel(tsc, LPC32XX_TSC_CON, tmp);
/* These values are all preset */
tsc_writel(tsc, LPC32XX_TSC_SEL, LPC32XX_TSC_SEL_DEFVAL);
tsc_writel(tsc, LPC32XX_TSC_MIN_X, LPC32XX_TSC_MIN_XY_VAL);
tsc_writel(tsc, LPC32XX_TSC_MAX_X, LPC32XX_TSC_MAX_XY_VAL);
tsc_writel(tsc, LPC32XX_TSC_MIN_Y, LPC32XX_TSC_MIN_XY_VAL);
tsc_writel(tsc, LPC32XX_TSC_MAX_Y, LPC32XX_TSC_MAX_XY_VAL);
/* Aux support is not used */
tsc_writel(tsc, LPC32XX_TSC_AUX_UTR, 0);
tsc_writel(tsc, LPC32XX_TSC_AUX_MIN, 0);
tsc_writel(tsc, LPC32XX_TSC_AUX_MAX, 0);
/*
* Set sample rate to about 240Hz per X/Y pair. A single measurement
* consists of 4 pairs which gives about a 60Hz sample rate based on
* a stable 32768Hz clock source. Values are in clocks.
* Rate is (32768 / (RTR + XCONV + RTR + YCONV + DXP + TTR + UTR) / 4
*/
tsc_writel(tsc, LPC32XX_TSC_RTR, 0x2);
tsc_writel(tsc, LPC32XX_TSC_DTR, 0x2);
tsc_writel(tsc, LPC32XX_TSC_TTR, 0x10);
tsc_writel(tsc, LPC32XX_TSC_DXP, 0x4);
tsc_writel(tsc, LPC32XX_TSC_UTR, 88);
lpc32xx_fifo_clear(tsc);
/* Enable automatic ts event capture */
tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN);
}
static int lpc32xx_ts_open(struct input_dev *dev)
{
struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
lpc32xx_setup_tsc(tsc);
return 0;
}
static void lpc32xx_ts_close(struct input_dev *dev)
{
struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
lpc32xx_stop_tsc(tsc);
}
static int lpc32xx_ts_probe(struct platform_device *pdev)
{
struct lpc32xx_tsc *tsc;
struct input_dev *input;
struct resource *res;
resource_size_t size;
int irq;
int error;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "Can't get memory resource\n");
return -ENOENT;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "Can't get interrupt resource\n");
return irq;
}
tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
input = input_allocate_device();
if (!tsc || !input) {
dev_err(&pdev->dev, "failed allocating memory\n");
error = -ENOMEM;
goto err_free_mem;
}
tsc->dev = input;
tsc->irq = irq;
size = resource_size(res);
if (!request_mem_region(res->start, size, pdev->name)) {
dev_err(&pdev->dev, "TSC registers are not free\n");
error = -EBUSY;
goto err_free_mem;
}
tsc->tsc_base = ioremap(res->start, size);
if (!tsc->tsc_base) {
dev_err(&pdev->dev, "Can't map memory\n");
error = -ENOMEM;
goto err_release_mem;
}
tsc->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(tsc->clk)) {
dev_err(&pdev->dev, "failed getting clock\n");
error = PTR_ERR(tsc->clk);
goto err_unmap;
}
input->name = MOD_NAME;
input->phys = "lpc32xx/input0";
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0002;
input->id.version = 0x0100;
input->dev.parent = &pdev->dev;
input->open = lpc32xx_ts_open;
input->close = lpc32xx_ts_close;
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,
LPC32XX_TSC_MAX_XY_VAL, 0, 0);
input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,
LPC32XX_TSC_MAX_XY_VAL, 0, 0);
input_set_drvdata(input, tsc);
error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
0, pdev->name, tsc);
if (error) {
dev_err(&pdev->dev, "failed requesting interrupt\n");
goto err_put_clock;
}
error = input_register_device(input);
if (error) {
dev_err(&pdev->dev, "failed registering input device\n");
goto err_free_irq;
}
platform_set_drvdata(pdev, tsc);
device_init_wakeup(&pdev->dev, 1);
return 0;
err_free_irq:
free_irq(tsc->irq, tsc);
err_put_clock:
clk_put(tsc->clk);
err_unmap:
iounmap(tsc->tsc_base);
err_release_mem:
release_mem_region(res->start, size);
err_free_mem:
input_free_device(input);
kfree(tsc);
return error;
}
static int lpc32xx_ts_remove(struct platform_device *pdev)
{
struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);
struct resource *res;
device_init_wakeup(&pdev->dev, 0);
free_irq(tsc->irq, tsc);
input_unregister_device(tsc->dev);
clk_put(tsc->clk);
iounmap(tsc->tsc_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
kfree(tsc);
return 0;
}
#ifdef CONFIG_PM
static int lpc32xx_ts_suspend(struct device *dev)
{
struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
struct input_dev *input = tsc->dev;
/*
* Suspend and resume can be called when the device hasn't been
* enabled. If there are no users that have the device open, then
* avoid calling the TSC stop and start functions as the TSC
* isn't yet clocked.
*/
mutex_lock(&input->mutex);
if (input->users) {
if (device_may_wakeup(dev))
enable_irq_wake(tsc->irq);
else
lpc32xx_stop_tsc(tsc);
}
mutex_unlock(&input->mutex);
return 0;
}
static int lpc32xx_ts_resume(struct device *dev)
{
struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
struct input_dev *input = tsc->dev;
mutex_lock(&input->mutex);
if (input->users) {
if (device_may_wakeup(dev))
disable_irq_wake(tsc->irq);
else
lpc32xx_setup_tsc(tsc);
}
mutex_unlock(&input->mutex);
return 0;
}
static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
.suspend = lpc32xx_ts_suspend,
.resume = lpc32xx_ts_resume,
};
#define LPC32XX_TS_PM_OPS (&lpc32xx_ts_pm_ops)
#else
#define LPC32XX_TS_PM_OPS NULL
#endif
#ifdef CONFIG_OF
static const struct of_device_id lpc32xx_tsc_of_match[] = {
{ .compatible = "nxp,lpc3220-tsc", },
{ },
};
MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match);
#endif
static struct platform_driver lpc32xx_ts_driver = {
.probe = lpc32xx_ts_probe,
.remove = lpc32xx_ts_remove,
.driver = {
.name = MOD_NAME,
.owner = THIS_MODULE,
.pm = LPC32XX_TS_PM_OPS,
.of_match_table = of_match_ptr(lpc32xx_tsc_of_match),
},
};
module_platform_driver(lpc32xx_ts_driver);
MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com");
MODULE_DESCRIPTION("LPC32XX TSC Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:lpc32xx_ts");

View file

@ -0,0 +1,309 @@
/*
* mainstone-wm97xx.c -- Mainstone Continuous Touch screen driver for
* Wolfson WM97xx AC97 Codecs.
*
* Copyright 2004, 2007 Wolfson Microelectronics PLC.
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* Notes:
* This is a wm97xx extended touch driver to capture touch
* data in a continuous manner on the Intel XScale architecture
*
* Features:
* - codecs supported:- WM9705, WM9712, WM9713
* - processors supported:- Intel XScale PXA25x, PXA26x, PXA27x
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/wm97xx.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <mach/regs-ac97.h>
#include <asm/mach-types.h>
struct continuous {
u16 id; /* codec id */
u8 code; /* continuous code */
u8 reads; /* number of coord reads per read cycle */
u32 speed; /* number of coords per second */
};
#define WM_READS(sp) ((sp / HZ) + 1)
static const struct continuous cinfo[] = {
{WM9705_ID2, 0, WM_READS(94), 94},
{WM9705_ID2, 1, WM_READS(188), 188},
{WM9705_ID2, 2, WM_READS(375), 375},
{WM9705_ID2, 3, WM_READS(750), 750},
{WM9712_ID2, 0, WM_READS(94), 94},
{WM9712_ID2, 1, WM_READS(188), 188},
{WM9712_ID2, 2, WM_READS(375), 375},
{WM9712_ID2, 3, WM_READS(750), 750},
{WM9713_ID2, 0, WM_READS(94), 94},
{WM9713_ID2, 1, WM_READS(120), 120},
{WM9713_ID2, 2, WM_READS(154), 154},
{WM9713_ID2, 3, WM_READS(188), 188},
};
/* continuous speed index */
static int sp_idx;
static u16 last, tries;
static int irq;
/*
* Pen sampling frequency (Hz) in continuous mode.
*/
static int cont_rate = 200;
module_param(cont_rate, int, 0);
MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
/*
* Pen down detection.
*
* This driver can either poll or use an interrupt to indicate a pen down
* event. If the irq request fails then it will fall back to polling mode.
*/
static int pen_int;
module_param(pen_int, int, 0);
MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
/*
* Pressure readback.
*
* Set to 1 to read back pen down pressure
*/
static int pressure;
module_param(pressure, int, 0);
MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
/*
* AC97 touch data slot.
*
* Touch screen readback data ac97 slot
*/
static int ac97_touch_slot = 5;
module_param(ac97_touch_slot, int, 0);
MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
/* flush AC97 slot 5 FIFO on pxa machines */
#ifdef CONFIG_PXA27x
static void wm97xx_acc_pen_up(struct wm97xx *wm)
{
schedule_timeout_uninterruptible(1);
while (MISR & (1 << 2))
MODR;
}
#else
static void wm97xx_acc_pen_up(struct wm97xx *wm)
{
unsigned int count;
schedule_timeout_uninterruptible(1);
for (count = 0; count < 16; count++)
MODR;
}
#endif
static int wm97xx_acc_pen_down(struct wm97xx *wm)
{
u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
int reads = 0;
/* When the AC97 queue has been drained we need to allow time
* to buffer up samples otherwise we end up spinning polling
* for samples. The controller can't have a suitably low
* threshold set to use the notifications it gives.
*/
schedule_timeout_uninterruptible(1);
if (tries > 5) {
tries = 0;
return RC_PENUP;
}
x = MODR;
if (x == last) {
tries++;
return RC_AGAIN;
}
last = x;
do {
if (reads)
x = MODR;
y = MODR;
if (pressure)
p = MODR;
dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
x, y, p);
/* are samples valid */
if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
(y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
(p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
goto up;
/* coordinate is good */
tries = 0;
input_report_abs(wm->input_dev, ABS_X, x & 0xfff);
input_report_abs(wm->input_dev, ABS_Y, y & 0xfff);
input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff);
input_report_key(wm->input_dev, BTN_TOUCH, (p != 0));
input_sync(wm->input_dev);
reads++;
} while (reads < cinfo[sp_idx].reads);
up:
return RC_PENDOWN | RC_AGAIN;
}
static int wm97xx_acc_startup(struct wm97xx *wm)
{
int idx = 0, ret = 0;
/* check we have a codec */
if (wm->ac97 == NULL)
return -ENODEV;
/* Go you big red fire engine */
for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
if (wm->id != cinfo[idx].id)
continue;
sp_idx = idx;
if (cont_rate <= cinfo[idx].speed)
break;
}
wm->acc_rate = cinfo[sp_idx].code;
wm->acc_slot = ac97_touch_slot;
dev_info(wm->dev,
"mainstone accelerated touchscreen driver, %d samples/sec\n",
cinfo[sp_idx].speed);
/* IRQ driven touchscreen is used on Palm hardware */
if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) {
pen_int = 1;
irq = 27;
/* There is some obscure mutant of WM9712 interbred with WM9713
* used on Palm HW */
wm->variant = WM97xx_WM1613;
} else if (machine_is_mainstone() && pen_int)
irq = 4;
if (irq) {
ret = gpio_request(irq, "Touchscreen IRQ");
if (ret)
goto out;
ret = gpio_direction_input(irq);
if (ret) {
gpio_free(irq);
goto out;
}
wm->pen_irq = gpio_to_irq(irq);
irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
} else /* pen irq not supported */
pen_int = 0;
/* codec specific irq config */
if (pen_int) {
switch (wm->id) {
case WM9705_ID2:
break;
case WM9712_ID2:
case WM9713_ID2:
/* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
WM97XX_GPIO_POL_HIGH,
WM97XX_GPIO_STICKY,
WM97XX_GPIO_WAKE);
wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
WM97XX_GPIO_POL_HIGH,
WM97XX_GPIO_NOTSTICKY,
WM97XX_GPIO_NOWAKE);
break;
default:
dev_err(wm->dev,
"pen down irq not supported on this device\n");
pen_int = 0;
break;
}
}
out:
return ret;
}
static void wm97xx_acc_shutdown(struct wm97xx *wm)
{
/* codec specific deconfig */
if (pen_int) {
if (irq)
gpio_free(irq);
wm->pen_irq = 0;
}
}
static void wm97xx_irq_enable(struct wm97xx *wm, int enable)
{
if (enable)
enable_irq(wm->pen_irq);
else
disable_irq_nosync(wm->pen_irq);
}
static struct wm97xx_mach_ops mainstone_mach_ops = {
.acc_enabled = 1,
.acc_pen_up = wm97xx_acc_pen_up,
.acc_pen_down = wm97xx_acc_pen_down,
.acc_startup = wm97xx_acc_startup,
.acc_shutdown = wm97xx_acc_shutdown,
.irq_enable = wm97xx_irq_enable,
.irq_gpio = WM97XX_GPIO_2,
};
static int mainstone_wm97xx_probe(struct platform_device *pdev)
{
struct wm97xx *wm = platform_get_drvdata(pdev);
return wm97xx_register_mach_ops(wm, &mainstone_mach_ops);
}
static int mainstone_wm97xx_remove(struct platform_device *pdev)
{
struct wm97xx *wm = platform_get_drvdata(pdev);
wm97xx_unregister_mach_ops(wm);
return 0;
}
static struct platform_driver mainstone_wm97xx_driver = {
.probe = mainstone_wm97xx_probe,
.remove = mainstone_wm97xx_remove,
.driver = {
.name = "wm97xx-touch",
},
};
module_platform_driver(mainstone_wm97xx_driver);
/* Module information */
MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
MODULE_DESCRIPTION("wm97xx continuous touch driver for mainstone");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,242 @@
/*
* Driver for MAXI MAX11801 - A Resistive touch screen controller with
* i2c interface
*
* Copyright (C) 2011 Freescale Semiconductor, Inc.
* Author: Zhang Jiejing <jiejing.zhang@freescale.com>
*
* Based on mcs5000_ts.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
/*
* This driver aims to support the series of MAXI touch chips max11801
* through max11803. The main difference between these 4 chips can be
* found in the table below:
* -----------------------------------------------------
* | CHIP | AUTO MODE SUPPORT(FIFO) | INTERFACE |
* |----------------------------------------------------|
* | max11800 | YES | SPI |
* | max11801 | YES | I2C |
* | max11802 | NO | SPI |
* | max11803 | NO | I2C |
* ------------------------------------------------------
*
* Currently, this driver only supports max11801.
*
* Data Sheet:
* http://www.maxim-ic.com/datasheet/index.mvp/id/5943
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/bitops.h>
/* Register Address define */
#define GENERNAL_STATUS_REG 0x00
#define GENERNAL_CONF_REG 0x01
#define MESURE_RES_CONF_REG 0x02
#define MESURE_AVER_CONF_REG 0x03
#define ADC_SAMPLE_TIME_CONF_REG 0x04
#define PANEL_SETUPTIME_CONF_REG 0x05
#define DELAY_CONVERSION_CONF_REG 0x06
#define TOUCH_DETECT_PULLUP_CONF_REG 0x07
#define AUTO_MODE_TIME_CONF_REG 0x08 /* only for max11800/max11801 */
#define APERTURE_CONF_REG 0x09 /* only for max11800/max11801 */
#define AUX_MESURE_CONF_REG 0x0a
#define OP_MODE_CONF_REG 0x0b
/* FIFO is found only in max11800 and max11801 */
#define FIFO_RD_CMD (0x50 << 1)
#define MAX11801_FIFO_INT (1 << 2)
#define MAX11801_FIFO_OVERFLOW (1 << 3)
#define XY_BUFSIZE 4
#define XY_BUF_OFFSET 4
#define MAX11801_MAX_X 0xfff
#define MAX11801_MAX_Y 0xfff
#define MEASURE_TAG_OFFSET 2
#define MEASURE_TAG_MASK (3 << MEASURE_TAG_OFFSET)
#define EVENT_TAG_OFFSET 0
#define EVENT_TAG_MASK (3 << EVENT_TAG_OFFSET)
#define MEASURE_X_TAG (0 << MEASURE_TAG_OFFSET)
#define MEASURE_Y_TAG (1 << MEASURE_TAG_OFFSET)
/* These are the state of touch event state machine */
enum {
EVENT_INIT,
EVENT_MIDDLE,
EVENT_RELEASE,
EVENT_FIFO_END
};
struct max11801_data {
struct i2c_client *client;
struct input_dev *input_dev;
};
static u8 read_register(struct i2c_client *client, int addr)
{
/* XXX: The chip ignores LSB of register address */
return i2c_smbus_read_byte_data(client, addr << 1);
}
static int max11801_write_reg(struct i2c_client *client, int addr, int data)
{
/* XXX: The chip ignores LSB of register address */
return i2c_smbus_write_byte_data(client, addr << 1, data);
}
static irqreturn_t max11801_ts_interrupt(int irq, void *dev_id)
{
struct max11801_data *data = dev_id;
struct i2c_client *client = data->client;
int status, i, ret;
u8 buf[XY_BUFSIZE];
int x = -1;
int y = -1;
status = read_register(data->client, GENERNAL_STATUS_REG);
if (status & (MAX11801_FIFO_INT | MAX11801_FIFO_OVERFLOW)) {
status = read_register(data->client, GENERNAL_STATUS_REG);
ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD,
XY_BUFSIZE, buf);
/*
* We should get 4 bytes buffer that contains X,Y
* and event tag
*/
if (ret < XY_BUFSIZE)
goto out;
for (i = 0; i < XY_BUFSIZE; i += XY_BUFSIZE / 2) {
if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_X_TAG)
x = (buf[i] << XY_BUF_OFFSET) +
(buf[i + 1] >> XY_BUF_OFFSET);
else if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_Y_TAG)
y = (buf[i] << XY_BUF_OFFSET) +
(buf[i + 1] >> XY_BUF_OFFSET);
}
if ((buf[1] & EVENT_TAG_MASK) != (buf[3] & EVENT_TAG_MASK))
goto out;
switch (buf[1] & EVENT_TAG_MASK) {
case EVENT_INIT:
/* fall through */
case EVENT_MIDDLE:
input_report_abs(data->input_dev, ABS_X, x);
input_report_abs(data->input_dev, ABS_Y, y);
input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1);
input_sync(data->input_dev);
break;
case EVENT_RELEASE:
input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(data->input_dev);
break;
case EVENT_FIFO_END:
break;
}
}
out:
return IRQ_HANDLED;
}
static void max11801_ts_phy_init(struct max11801_data *data)
{
struct i2c_client *client = data->client;
/* Average X,Y, take 16 samples, average eight media sample */
max11801_write_reg(client, MESURE_AVER_CONF_REG, 0xff);
/* X,Y panel setup time set to 20us */
max11801_write_reg(client, PANEL_SETUPTIME_CONF_REG, 0x11);
/* Rough pullup time (2uS), Fine pullup time (10us) */
max11801_write_reg(client, TOUCH_DETECT_PULLUP_CONF_REG, 0x10);
/* Auto mode init period = 5ms , scan period = 5ms*/
max11801_write_reg(client, AUTO_MODE_TIME_CONF_REG, 0xaa);
/* Aperture X,Y set to +- 4LSB */
max11801_write_reg(client, APERTURE_CONF_REG, 0x33);
/* Enable Power, enable Automode, enable Aperture, enable Average X,Y */
max11801_write_reg(client, OP_MODE_CONF_REG, 0x36);
}
static int max11801_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max11801_data *data;
struct input_dev *input_dev;
int error;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
input_dev = devm_input_allocate_device(&client->dev);
if (!data || !input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
data->client = client;
data->input_dev = input_dev;
input_dev->name = "max11801_ts";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, 0, MAX11801_MAX_X, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, MAX11801_MAX_Y, 0, 0);
input_set_drvdata(input_dev, data);
max11801_ts_phy_init(data);
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
max11801_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"max11801_ts", data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
return error;
}
error = input_register_device(data->input_dev);
if (error)
return error;
i2c_set_clientdata(client, data);
return 0;
}
static const struct i2c_device_id max11801_ts_id[] = {
{"max11801", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
static struct i2c_driver max11801_ts_driver = {
.driver = {
.name = "max11801_ts",
.owner = THIS_MODULE,
},
.id_table = max11801_ts_id,
.probe = max11801_ts_probe,
};
module_i2c_driver(max11801_ts_driver);
MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
MODULE_DESCRIPTION("Touchscreen driver for MAXI MAX11801 controller");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,256 @@
/*
* Driver for the Freescale Semiconductor MC13783 touchscreen.
*
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright (C) 2009 Sascha Hauer, Pengutronix
*
* Initial development of this code was funded by
* Phytec Messtechnik GmbH, http://www.phytec.de/
*
* 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/platform_device.h>
#include <linux/mfd/mc13783.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
#define MC13783_TS_NAME "mc13783-ts"
#define DEFAULT_SAMPLE_TOLERANCE 300
static unsigned int sample_tolerance = DEFAULT_SAMPLE_TOLERANCE;
module_param(sample_tolerance, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(sample_tolerance,
"If the minimal and maximal value read out for one axis (out "
"of three) differ by this value (default: "
__stringify(DEFAULT_SAMPLE_TOLERANCE) ") or more, the reading "
"is supposed to be wrong and is discarded. Set to 0 to "
"disable this check.");
struct mc13783_ts_priv {
struct input_dev *idev;
struct mc13xxx *mc13xxx;
struct delayed_work work;
struct workqueue_struct *workq;
unsigned int sample[4];
struct mc13xxx_ts_platform_data *touch;
};
static irqreturn_t mc13783_ts_handler(int irq, void *data)
{
struct mc13783_ts_priv *priv = data;
mc13xxx_irq_ack(priv->mc13xxx, irq);
/*
* Kick off reading coordinates. Note that if work happens already
* be queued for future execution (it rearms itself) it will not
* be rescheduled for immediate execution here. However the rearm
* delay is HZ / 50 which is acceptable.
*/
queue_delayed_work(priv->workq, &priv->work, 0);
return IRQ_HANDLED;
}
#define sort3(a0, a1, a2) ({ \
if (a0 > a1) \
swap(a0, a1); \
if (a1 > a2) \
swap(a1, a2); \
if (a0 > a1) \
swap(a0, a1); \
})
static void mc13783_ts_report_sample(struct mc13783_ts_priv *priv)
{
struct input_dev *idev = priv->idev;
int x0, x1, x2, y0, y1, y2;
int cr0, cr1;
/*
* the values are 10-bit wide only, but the two least significant
* bits are for future 12 bit use and reading yields 0
*/
x0 = priv->sample[0] & 0xfff;
x1 = priv->sample[1] & 0xfff;
x2 = priv->sample[2] & 0xfff;
y0 = priv->sample[3] & 0xfff;
y1 = (priv->sample[0] >> 12) & 0xfff;
y2 = (priv->sample[1] >> 12) & 0xfff;
cr0 = (priv->sample[2] >> 12) & 0xfff;
cr1 = (priv->sample[3] >> 12) & 0xfff;
dev_dbg(&idev->dev,
"x: (% 4d,% 4d,% 4d) y: (% 4d, % 4d,% 4d) cr: (% 4d, % 4d)\n",
x0, x1, x2, y0, y1, y2, cr0, cr1);
sort3(x0, x1, x2);
sort3(y0, y1, y2);
cr0 = (cr0 + cr1) / 2;
if (!cr0 || !sample_tolerance ||
(x2 - x0 < sample_tolerance &&
y2 - y0 < sample_tolerance)) {
/* report the median coordinate and average pressure */
if (cr0) {
input_report_abs(idev, ABS_X, x1);
input_report_abs(idev, ABS_Y, y1);
dev_dbg(&idev->dev, "report (%d, %d, %d)\n",
x1, y1, 0x1000 - cr0);
queue_delayed_work(priv->workq, &priv->work, HZ / 50);
} else
dev_dbg(&idev->dev, "report release\n");
input_report_abs(idev, ABS_PRESSURE,
cr0 ? 0x1000 - cr0 : cr0);
input_report_key(idev, BTN_TOUCH, cr0);
input_sync(idev);
} else
dev_dbg(&idev->dev, "discard event\n");
}
static void mc13783_ts_work(struct work_struct *work)
{
struct mc13783_ts_priv *priv =
container_of(work, struct mc13783_ts_priv, work.work);
unsigned int mode = MC13XXX_ADC_MODE_TS;
unsigned int channel = 12;
if (mc13xxx_adc_do_conversion(priv->mc13xxx,
mode, channel,
priv->touch->ato, priv->touch->atox,
priv->sample) == 0)
mc13783_ts_report_sample(priv);
}
static int mc13783_ts_open(struct input_dev *dev)
{
struct mc13783_ts_priv *priv = input_get_drvdata(dev);
int ret;
mc13xxx_lock(priv->mc13xxx);
mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TS);
ret = mc13xxx_irq_request(priv->mc13xxx, MC13XXX_IRQ_TS,
mc13783_ts_handler, MC13783_TS_NAME, priv);
if (ret)
goto out;
ret = mc13xxx_reg_rmw(priv->mc13xxx, MC13XXX_ADC0,
MC13XXX_ADC0_TSMOD_MASK, MC13XXX_ADC0_TSMOD0);
if (ret)
mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TS, priv);
out:
mc13xxx_unlock(priv->mc13xxx);
return ret;
}
static void mc13783_ts_close(struct input_dev *dev)
{
struct mc13783_ts_priv *priv = input_get_drvdata(dev);
mc13xxx_lock(priv->mc13xxx);
mc13xxx_reg_rmw(priv->mc13xxx, MC13XXX_ADC0,
MC13XXX_ADC0_TSMOD_MASK, 0);
mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TS, priv);
mc13xxx_unlock(priv->mc13xxx);
cancel_delayed_work_sync(&priv->work);
}
static int __init mc13783_ts_probe(struct platform_device *pdev)
{
struct mc13783_ts_priv *priv;
struct input_dev *idev;
int ret = -ENOMEM;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
idev = input_allocate_device();
if (!priv || !idev)
goto err_free_mem;
INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
priv->idev = idev;
priv->touch = dev_get_platdata(&pdev->dev);
if (!priv->touch) {
dev_err(&pdev->dev, "missing platform data\n");
ret = -ENODEV;
goto err_free_mem;
}
/*
* We need separate workqueue because mc13783_adc_do_conversion
* uses keventd and thus would deadlock.
*/
priv->workq = create_singlethread_workqueue("mc13783_ts");
if (!priv->workq)
goto err_free_mem;
idev->name = MC13783_TS_NAME;
idev->dev.parent = &pdev->dev;
idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(idev, ABS_X, 0, 0xfff, 0, 0);
input_set_abs_params(idev, ABS_Y, 0, 0xfff, 0, 0);
input_set_abs_params(idev, ABS_PRESSURE, 0, 0xfff, 0, 0);
idev->open = mc13783_ts_open;
idev->close = mc13783_ts_close;
input_set_drvdata(idev, priv);
ret = input_register_device(priv->idev);
if (ret) {
dev_err(&pdev->dev,
"register input device failed with %d\n", ret);
goto err_destroy_wq;
}
platform_set_drvdata(pdev, priv);
return 0;
err_destroy_wq:
destroy_workqueue(priv->workq);
err_free_mem:
input_free_device(idev);
kfree(priv);
return ret;
}
static int mc13783_ts_remove(struct platform_device *pdev)
{
struct mc13783_ts_priv *priv = platform_get_drvdata(pdev);
destroy_workqueue(priv->workq);
input_unregister_device(priv->idev);
kfree(priv);
return 0;
}
static struct platform_driver mc13783_ts_driver = {
.remove = mc13783_ts_remove,
.driver = {
.owner = THIS_MODULE,
.name = MC13783_TS_NAME,
},
};
module_platform_driver_probe(mc13783_ts_driver, mc13783_ts_probe);
MODULE_DESCRIPTION("MC13783 input touchscreen driver");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" MC13783_TS_NAME);

View file

@ -0,0 +1,294 @@
/*
* mcs5000_ts.c - Touchscreen driver for MELFAS MCS-5000 controller
*
* Copyright (C) 2009 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* Based on wm97xx-core.c
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/i2c/mcs.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/slab.h>
/* Registers */
#define MCS5000_TS_STATUS 0x00
#define STATUS_OFFSET 0
#define STATUS_NO (0 << STATUS_OFFSET)
#define STATUS_INIT (1 << STATUS_OFFSET)
#define STATUS_SENSING (2 << STATUS_OFFSET)
#define STATUS_COORD (3 << STATUS_OFFSET)
#define STATUS_GESTURE (4 << STATUS_OFFSET)
#define ERROR_OFFSET 4
#define ERROR_NO (0 << ERROR_OFFSET)
#define ERROR_POWER_ON_RESET (1 << ERROR_OFFSET)
#define ERROR_INT_RESET (2 << ERROR_OFFSET)
#define ERROR_EXT_RESET (3 << ERROR_OFFSET)
#define ERROR_INVALID_REG_ADDRESS (8 << ERROR_OFFSET)
#define ERROR_INVALID_REG_VALUE (9 << ERROR_OFFSET)
#define MCS5000_TS_OP_MODE 0x01
#define RESET_OFFSET 0
#define RESET_NO (0 << RESET_OFFSET)
#define RESET_EXT_SOFT (1 << RESET_OFFSET)
#define OP_MODE_OFFSET 1
#define OP_MODE_SLEEP (0 << OP_MODE_OFFSET)
#define OP_MODE_ACTIVE (1 << OP_MODE_OFFSET)
#define GESTURE_OFFSET 4
#define GESTURE_DISABLE (0 << GESTURE_OFFSET)
#define GESTURE_ENABLE (1 << GESTURE_OFFSET)
#define PROXIMITY_OFFSET 5
#define PROXIMITY_DISABLE (0 << PROXIMITY_OFFSET)
#define PROXIMITY_ENABLE (1 << PROXIMITY_OFFSET)
#define SCAN_MODE_OFFSET 6
#define SCAN_MODE_INTERRUPT (0 << SCAN_MODE_OFFSET)
#define SCAN_MODE_POLLING (1 << SCAN_MODE_OFFSET)
#define REPORT_RATE_OFFSET 7
#define REPORT_RATE_40 (0 << REPORT_RATE_OFFSET)
#define REPORT_RATE_80 (1 << REPORT_RATE_OFFSET)
#define MCS5000_TS_SENS_CTL 0x02
#define MCS5000_TS_FILTER_CTL 0x03
#define PRI_FILTER_OFFSET 0
#define SEC_FILTER_OFFSET 4
#define MCS5000_TS_X_SIZE_UPPER 0x08
#define MCS5000_TS_X_SIZE_LOWER 0x09
#define MCS5000_TS_Y_SIZE_UPPER 0x0A
#define MCS5000_TS_Y_SIZE_LOWER 0x0B
#define MCS5000_TS_INPUT_INFO 0x10
#define INPUT_TYPE_OFFSET 0
#define INPUT_TYPE_NONTOUCH (0 << INPUT_TYPE_OFFSET)
#define INPUT_TYPE_SINGLE (1 << INPUT_TYPE_OFFSET)
#define INPUT_TYPE_DUAL (2 << INPUT_TYPE_OFFSET)
#define INPUT_TYPE_PALM (3 << INPUT_TYPE_OFFSET)
#define INPUT_TYPE_PROXIMITY (7 << INPUT_TYPE_OFFSET)
#define GESTURE_CODE_OFFSET 3
#define GESTURE_CODE_NO (0 << GESTURE_CODE_OFFSET)
#define MCS5000_TS_X_POS_UPPER 0x11
#define MCS5000_TS_X_POS_LOWER 0x12
#define MCS5000_TS_Y_POS_UPPER 0x13
#define MCS5000_TS_Y_POS_LOWER 0x14
#define MCS5000_TS_Z_POS 0x15
#define MCS5000_TS_WIDTH 0x16
#define MCS5000_TS_GESTURE_VAL 0x17
#define MCS5000_TS_MODULE_REV 0x20
#define MCS5000_TS_FIRMWARE_VER 0x21
/* Touchscreen absolute values */
#define MCS5000_MAX_XC 0x3ff
#define MCS5000_MAX_YC 0x3ff
enum mcs5000_ts_read_offset {
READ_INPUT_INFO,
READ_X_POS_UPPER,
READ_X_POS_LOWER,
READ_Y_POS_UPPER,
READ_Y_POS_LOWER,
READ_BLOCK_SIZE,
};
/* Each client has this additional data */
struct mcs5000_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
const struct mcs_platform_data *platform_data;
};
static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
{
struct mcs5000_ts_data *data = dev_id;
struct i2c_client *client = data->client;
u8 buffer[READ_BLOCK_SIZE];
int err;
int x;
int y;
err = i2c_smbus_read_i2c_block_data(client, MCS5000_TS_INPUT_INFO,
READ_BLOCK_SIZE, buffer);
if (err < 0) {
dev_err(&client->dev, "%s, err[%d]\n", __func__, err);
goto out;
}
switch (buffer[READ_INPUT_INFO]) {
case INPUT_TYPE_NONTOUCH:
input_report_key(data->input_dev, BTN_TOUCH, 0);
input_sync(data->input_dev);
break;
case INPUT_TYPE_SINGLE:
x = (buffer[READ_X_POS_UPPER] << 8) | buffer[READ_X_POS_LOWER];
y = (buffer[READ_Y_POS_UPPER] << 8) | buffer[READ_Y_POS_LOWER];
input_report_key(data->input_dev, BTN_TOUCH, 1);
input_report_abs(data->input_dev, ABS_X, x);
input_report_abs(data->input_dev, ABS_Y, y);
input_sync(data->input_dev);
break;
case INPUT_TYPE_DUAL:
/* TODO */
break;
case INPUT_TYPE_PALM:
/* TODO */
break;
case INPUT_TYPE_PROXIMITY:
/* TODO */
break;
default:
dev_err(&client->dev, "Unknown ts input type %d\n",
buffer[READ_INPUT_INFO]);
break;
}
out:
return IRQ_HANDLED;
}
static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data,
const struct mcs_platform_data *platform_data)
{
struct i2c_client *client = data->client;
/* Touch reset & sleep mode */
i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE,
RESET_EXT_SOFT | OP_MODE_SLEEP);
/* Touch size */
i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_UPPER,
platform_data->x_size >> 8);
i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_LOWER,
platform_data->x_size & 0xff);
i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_UPPER,
platform_data->y_size >> 8);
i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_LOWER,
platform_data->y_size & 0xff);
/* Touch active mode & 80 report rate */
i2c_smbus_write_byte_data(data->client, MCS5000_TS_OP_MODE,
OP_MODE_ACTIVE | REPORT_RATE_80);
}
static int mcs5000_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct mcs_platform_data *pdata;
struct mcs5000_ts_data *data;
struct input_dev *input_dev;
int error;
pdata = dev_get_platdata(&client->dev);
if (!pdata)
return -EINVAL;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
data->client = client;
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev) {
dev_err(&client->dev, "Failed to allocate input device\n");
return -ENOMEM;
}
input_dev->name = "MELFAS MCS-5000 Touchscreen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
input_set_drvdata(input_dev, data);
data->input_dev = input_dev;
if (pdata->cfg_pin)
pdata->cfg_pin();
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, mcs5000_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"mcs5000_ts", data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
return error;
}
error = input_register_device(data->input_dev);
if (error) {
dev_err(&client->dev, "Failed to register input device\n");
return error;
}
mcs5000_ts_phys_init(data, pdata);
i2c_set_clientdata(client, data);
return 0;
}
static int __maybe_unused mcs5000_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
/* Touch sleep mode */
i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP);
return 0;
}
static int __maybe_unused mcs5000_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
const struct mcs_platform_data *pdata = dev_get_platdata(dev);
mcs5000_ts_phys_init(data, pdata);
return 0;
}
static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
static const struct i2c_device_id mcs5000_ts_id[] = {
{ "mcs5000_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
static struct i2c_driver mcs5000_ts_driver = {
.probe = mcs5000_ts_probe,
.driver = {
.name = "mcs5000_ts",
.pm = &mcs5000_ts_pm,
},
.id_table = mcs5000_ts_id,
};
module_i2c_driver(mcs5000_ts_driver);
/* Module information */
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
MODULE_DESCRIPTION("Touchscreen driver for MELFAS MCS-5000 controller");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,48 @@
#
# Kconfig for MELFAS MMS400 Touchscreen driver
#
if INPUT_TOUCHSCREEN
config TOUCHSCREEN_MELFAS_MMS438
tristate "MELFAS MMS438 Touchscreen"
depends on I2C
help
Say Y here if you have a MELFAS MMS438 touchscreen device in your system.
# If unsure, say N.
# To compile this driver as a module, choose M here: the module will be called mms_ts.
config TOUCHSCREEN_MELFAS_MMS449
tristate "MELFAS MMS449 Touchscreen"
depends on I2C
help
Say Y here if you have a MELFAS MMS449 touchscreen device in your system.
# If unsure, say N.
# To compile this driver as a module, choose M here: the module will be called mms_ts.
config TOUCHSCREEN_MELFAS_MMS458
tristate "MELFAS MMS458 Touchscreen"
depends on I2C
help
Say Y here if you have a MELFAS MMS458 touchscreen device in your system.
# If unsure, say N.
# To compile this driver as a module, choose M here: the module will be called mms_ts.
config TOUCHSCREEN_MELFAS_MMS492
tristate "MELFAS MMS492 Touchscreen"
depends on I2C
help
Say Y here if you have a MELFAS MMS492 touchscreen device in your system.
# If unsure, say N.
# To compile this driver as a module, choose M here: the module will be called mms_ts.
endif

View file

@ -0,0 +1,15 @@
#
# Makefile for MELFAS MMS400 Touchscreen driver
#
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MMS438) += melfas_mms400.o melfas_mms400_mod.o melfas_mms400_test.o melfas_mms400_cmd.o melfas_mms438_fw_update.o
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MMS449) += melfas_mms400.o melfas_mms400_mod.o melfas_mms400_test.o melfas_mms400_cmd.o melfas_mms438_fw_update.o
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MMS458) += melfas_mms400.o melfas_mms400_mod.o melfas_mms400_test.o melfas_mms400_cmd.o melfas_mms438_fw_update.o
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MMS492) += melfas_mms400.o melfas_mms400_mod.o melfas_mms400_test.o melfas_mms400_cmd.o melfas_mms492_fw_update.o
#CFLAGS_melfas_mms400.o += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-label
#CFLAGS_melfas_mms400_test.o += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-label
#CFLAGS_melfas_mms400_cmd.o += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-label
#CFLAGS_melfas_mms438_fw_update.o += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-label
#CFLAGS_melfas_mms492_fw_update.o += -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-unused-label

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,407 @@
/*
* MELFAS MMS400 Touchscreen Driver
*
* Copyright (C) 2014 MELFAS Inc.
*
*/
#ifndef __MELFAS_MMS400_H
#define __MELFAS_MMS400_H
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/cdev.h>
#include <linux/err.h>
#include <linux/limits.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/gpio_event.h>
#include <linux/wakelock.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include "melfas_mms400_reg.h"
#include <linux/sec_sysfs.h>
#ifdef CONFIG_BATTERY_SAMSUNG
#include <linux/sec_batt.h>
#endif
#ifdef CONFIG_VBUS_NOTIFIER
#include <linux/muic/muic.h>
#include <linux/muic/muic_notifier.h>
#include <linux/vbus_notifier.h>
#endif
#ifdef CONFIG_SEC_DEBUG_TSP_LOG
#include <linux/sec_debug.h>
#endif
#ifdef CONFIG_SEC_DEBUG_TSP_LOG
#define tsp_debug_dbg(mode, dev, fmt, ...) \
({ \
if (mode) { \
dev_dbg(dev, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
else \
dev_dbg(dev, fmt, ## __VA_ARGS__); \
})
#define tsp_debug_info(mode, dev, fmt, ...) \
({ \
if (mode) { \
dev_info(dev, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
else \
dev_info(dev, fmt, ## __VA_ARGS__); \
})
#define tsp_debug_err(mode, dev, fmt, ...) \
({ \
if (mode) { \
dev_err(dev, fmt, ## __VA_ARGS__); \
sec_debug_tsp_log(fmt, ## __VA_ARGS__); \
} \
else \
dev_err(dev, fmt, ## __VA_ARGS__); \
})
#else
#define tsp_debug_dbg(mode, dev, fmt, ...) dev_dbg(dev, fmt, ## __VA_ARGS__)
#define tsp_debug_info(mode, dev, fmt, ...) dev_info(dev, fmt, ## __VA_ARGS__)
#define tsp_debug_err(mode, dev, fmt, ...) dev_err(dev, fmt, ## __VA_ARGS__)
#endif
#ifdef CONFIG_OF
#define MMS_USE_DEVICETREE 1
#else
#define MMS_USE_DEVICETREE 0
#endif
#if defined(CONFIG_GLOVE_TOUCH)
#define GLOVE_MODE
#endif
#define COVER_MODE
#define MMS_DEVICE_NAME "mms_ts"
#define MMS_CONFIG_DATE {0x00, 0x00, 0x00, 0x00}
//Chip info
#if defined(CONFIG_TOUCHSCREEN_MELFAS_MMS438)
#define CHIP_MMS438
#define CHIP_NAME "MMS438"
#define CHIP_FW_CODE "M4H0"
#define FW_UPDATE_TYPE "MMS438"
#elif defined(CONFIG_TOUCHSCREEN_MELFAS_MMS449)
#define CHIP_MMS449
#define CHIP_NAME "MMS449"
#define CHIP_FW_CODE "M4HP"
#define FW_UPDATE_TYPE "MMS438"
#elif defined(CONFIG_TOUCHSCREEN_MELFAS_MMS458)
#define CHIP_MMS458
#define CHIP_NAME "MMS458"
#define CHIP_FW_CODE "M4HN"
#define FW_UPDATE_TYPE "MMS438"
#elif defined(CONFIG_TOUCHSCREEN_MELFAS_MMS492)
#define CHIP_MMS492
#define CHIP_NAME "MMS492"
#define CHIP_FW_CODE "M4HL"
#define FW_UPDATE_TYPE "MMS492"
#endif
//Config driver
#define MMS_USE_INPUT_OPEN_CLOSE 1
#define I2C_RETRY_COUNT 3
#define RESET_ON_EVENT_ERROR 0
#define ESD_COUNT_FOR_DISABLE 7
#define MMS_USE_TOUCHKEY 0
//Features
#define MMS_USE_NAP_MODE 0
#define MMS_USE_TEST_MODE 1
#define MMS_USE_CMD_MODE 1
#ifdef CONFIG_SAMSUNG_PRODUCT_SHIP
#define MMS_USE_DEV_MODE 0
#else
#define MMS_USE_DEV_MODE 1
#endif
//Input value
#define MAX_FINGER_NUM 10
#define INPUT_AREA_MIN 0
#define INPUT_AREA_MAX 255
#define INPUT_PRESSURE_MIN 0
#define INPUT_PRESSURE_MAX 255
#define INPUT_TOUCH_MAJOR_MIN 0
#define INPUT_TOUCH_MAJOR_MAX 255
#define INPUT_TOUCH_MINOR_MIN 0
#define INPUT_TOUCH_MINOR_MAX 255
#define INPUT_ANGLE_MIN 0
#define INPUT_ANGLE_MAX 255
#define INPUT_HOVER_MIN 0
#define INPUT_HOVER_MAX 255
#define INPUT_PALM_MIN 0
#define INPUT_PALM_MAX 1
//Firmware update
#define INTERNAL_FW_PATH "tsp_melfas/mms449_carmen2.fw"
#define EXTERNAL_FW_PATH "/sdcard/melfas.mfsb"
#define FFU_FW_PATH "ffu_tsp.bin"
#define MMS_USE_AUTO_FW_UPDATE 1
#define MMS_FW_MAX_SECT_NUM 4
#define MMS_FW_UPDATE_DEBUG 0
#define MMS_FW_UPDATE_SECTION 1
#define MMS_EXT_FW_FORCE_UPDATE 1
//Command mode
#define CMD_LEN 32
#define CMD_RESULT_LEN 512
#define CMD_PARAM_NUM 8
/**
* Device info structure
*/
struct mms_ts_info {
struct i2c_client *client;
struct input_dev *input_dev;
char phys[32];
struct mms_devicetree_data *dtdata;
struct pinctrl *pinctrl;
dev_t mms_dev;
struct class *class;
struct mutex lock;
struct mutex lock_test;
struct mutex lock_cmd;
struct mutex lock_dev;
int irq;
bool enabled;
bool init;
char *fw_name;
u8 product_name[16];
int max_x;
int max_y;
u8 node_x;
u8 node_y;
u8 node_key;
u8 boot_ver_ic;
u8 core_ver_ic;
u8 config_ver_ic;
u8 event_size;
u16 fw_year;
u8 fw_month;
u8 fw_date;
u16 pre_chksum;
u16 rt_chksum;
unsigned char finger_state[MAX_FINGER_NUM];
int touch_count;
bool tkey_enable;
u8 nap_mode;
u8 glove_mode;
u8 charger_mode;
u8 cover_mode;
u8 esd_cnt;
bool disable_esd;
u8 *print_buf;
int *image_buf;
bool test_busy;
bool cmd_busy;
bool dev_busy;
#if MMS_USE_CMD_MODE
dev_t cmd_dev_t;
struct device *cmd_dev;
struct class *cmd_class;
struct list_head cmd_list_head;
u8 cmd_state;
char cmd[CMD_LEN];
char *cmd_result;
int cmd_param[CMD_PARAM_NUM];
int cmd_buffer_size;
#endif
#if MMS_USE_DEV_MODE
struct cdev cdev;
u8 *dev_fs_buf;
#endif
#ifdef CONFIG_VBUS_NOTIFIER
struct notifier_block vbus_nb;
bool ta_stsatus;
#endif
#ifdef USE_TSP_TA_CALLBACKS
void (*register_cb)(struct tsp_callbacks *);
struct tsp_callbacks callbacks;
#endif
#ifdef CONFIG_SEC_DEBUG_TSP_LOG
struct delayed_work ghost_check;
u8 tsp_dump_lock;
u8 add_log_header;
#endif
};
/**
* Platform Data
*/
struct mms_devicetree_data {
unsigned int max_x;
unsigned int max_y;
int gpio_intr;
const char *gpio_vdd_en;
const char *gpio_io_en;
int gpio_sda;
int gpio_scl;
int panel;
struct regulator *vdd_io;
const char *fw_name;
};
/**
* Firmware binary header info
*/
struct mms_bin_hdr {
char tag[8];
u16 core_version;
u16 section_num;
u16 contains_full_binary;
u16 reserved0;
u32 binary_offset;
u32 binary_length;
u32 extention_offset;
u32 reserved1;
} __attribute__ ((packed));
/**
* Firmware image info
*/
struct mms_fw_img {
u16 type;
u16 version;
u16 start_page;
u16 end_page;
u32 offset;
u32 length;
} __attribute__ ((packed));
/**
* Firmware update error code
*/
enum fw_update_errno{
fw_err_file_read = -4,
fw_err_file_open = -3,
fw_err_file_type = -2,
fw_err_download = -1,
fw_err_none = 0,
fw_err_uptodate = 1,
};
/**
* Declarations
*/
//main
void mms_reboot(struct mms_ts_info *info);
int mms_i2c_read(struct mms_ts_info *info, char *write_buf, unsigned int write_len,
char *read_buf, unsigned int read_len);
int mms_i2c_read_next(struct mms_ts_info *info, char *read_buf, int start_idx,
unsigned int read_len);
int mms_i2c_write(struct mms_ts_info *info, char *write_buf, unsigned int write_len);
int mms_enable(struct mms_ts_info *info);
int mms_disable(struct mms_ts_info *info);
int mms_get_ready_status(struct mms_ts_info *info);
int mms_get_fw_version(struct mms_ts_info *info, u8 *ver_buf);
int mms_get_fw_version_u16(struct mms_ts_info *info, u16 *ver_buf_u16);
int mms_disable_esd_alert(struct mms_ts_info *info);
int mms_fw_update_from_kernel(struct mms_ts_info *info, bool force);
int mms_fw_update_from_storage(struct mms_ts_info *info, bool force);
int mms_fw_update_from_ffu(struct mms_ts_info *info, bool force);
int mms_suspend(struct device *dev);
int mms_resume(struct device *dev);
//mod
int mms_power_control(struct mms_ts_info *info, int enable);
void mms_clear_input(struct mms_ts_info *info);
void mms_report_input_event(struct mms_ts_info *info, u8 sz, u8 *buf);
void mms_input_event_handler(struct mms_ts_info *info, u8 sz, u8 *buf);
#ifdef CONFIG_VBUS_NOTIFIER
int mms_charger_attached(struct mms_ts_info *info, bool status);
#endif
#if MMS_USE_DEVICETREE
int mms_parse_devicetree(struct device *dev, struct mms_ts_info *info);
#endif
void mms_config_input(struct mms_ts_info *info);
//fw_update
int mms_flash_fw(struct mms_ts_info *info, const u8 *fw_data, size_t fw_size,
bool force, bool section);
//test
#if MMS_USE_DEV_MODE
int mms_dev_create(struct mms_ts_info *info);
int mms_get_log(struct mms_ts_info *info);
#endif
int mms_run_test(struct mms_ts_info *info, u8 test_type);
int mms_get_image(struct mms_ts_info *info, u8 image_type);
#if MMS_USE_TEST_MODE
int mms_sysfs_create(struct mms_ts_info *info);
void mms_sysfs_remove(struct mms_ts_info *info);
static const struct attribute_group mms_test_attr_group;
#endif
//cmd
#if MMS_USE_CMD_MODE
int mms_sysfs_cmd_create(struct mms_ts_info *info);
void mms_sysfs_cmd_remove(struct mms_ts_info *info);
static const struct attribute_group mms_cmd_attr_group;
extern struct class *sec_class;
#endif
#ifdef USE_TSP_TA_CALLBACKS
void mms_charger_status_cb(struct tsp_callbacks *cb, int status);
void mms_register_callback(struct tsp_callbacks *cb);
#endif
#ifdef CONFIG_VBUS_NOTIFIER
int mms_vbus_notification(struct notifier_block *nb,
unsigned long cmd, void *data);
#endif
#ifdef CONFIG_SAMSUNG_LPM_MODE
extern int poweroff_charging;
#endif
#endif /* __MELFAS_MMS400_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,399 @@
/*
* MELFAS MMS400 Touchscreen
*
* Copyright (C) 2014 MELFAS Inc.
*
*
* Model dependent functions
*
*/
#include "melfas_mms400.h"
#ifdef USE_TSP_TA_CALLBACKS
static bool ta_connected = 0;
#endif
/**
* Control power supply
*/
int mms_power_control(struct mms_ts_info *info, int enable)
{
int ret = 0;
struct i2c_client *client = info->client;
struct regulator *regulator_dvdd;
struct regulator *regulator_avdd;
struct pinctrl_state *pinctrl_state;
static bool on;
tsp_debug_info(true, &info->client->dev, "%s [START %s] \n",
__func__, enable? "on":"off");
if (on == enable) {
tsp_debug_err(true, &client->dev, "%s : TSP power already %s\n",
__func__,(on)?"on":"off");
return ret;
}
if (info->dtdata->gpio_io_en) {
regulator_dvdd = regulator_get(NULL, info->dtdata->gpio_io_en);
if (IS_ERR(regulator_dvdd)) {
tsp_debug_err(true, &client->dev,"%s: Failed to get %s regulator.\n",
__func__, info->dtdata->gpio_io_en);
ret = PTR_ERR(regulator_dvdd);
goto out;
}
}
regulator_avdd = regulator_get(NULL, info->dtdata->gpio_vdd_en);
if (IS_ERR(regulator_avdd)) {
tsp_debug_err(true, &client->dev,"%s: Failed to get %s regulator.\n",
__func__, info->dtdata->gpio_vdd_en);
ret = PTR_ERR(regulator_avdd);
goto out;
}
if (enable) {
ret = regulator_enable(regulator_avdd);
if (ret) {
tsp_debug_err(true, &client->dev, "%s: Failed to enable avdd: %d\n", __func__, ret);
goto out;
}
if (info->dtdata->gpio_io_en) {
ret = regulator_enable(regulator_dvdd);
if (ret) {
tsp_debug_err(true, &client->dev,"%s: Failed to enable vdd: %d\n", __func__, ret);
goto out;
}
}
pinctrl_state = pinctrl_lookup_state(info->pinctrl, "on_state");
} else {
if (info->dtdata->gpio_io_en) {
if (regulator_is_enabled(regulator_dvdd))
regulator_disable(regulator_dvdd);
}
if (regulator_is_enabled(regulator_avdd))
regulator_disable(regulator_avdd);
pinctrl_state = pinctrl_lookup_state(info->pinctrl, "off_state");
}
if (IS_ERR(pinctrl_state)) {
tsp_debug_err(true, &client->dev,"%s: Failed to lookup pinctrl.\n", __func__);
} else {
ret = pinctrl_select_state(info->pinctrl, pinctrl_state);
if (ret)
tsp_debug_err(true, &client->dev, "%s: Failed to configure pinctrl.\n", __func__);
}
on = enable;
out:
if (info->dtdata->gpio_io_en) {
regulator_put(regulator_dvdd);
}
regulator_put(regulator_avdd);
if (!enable)
usleep_range(10 * 1000, 11 * 1000);
else
msleep(50);
tsp_debug_info(true, &info->client->dev, "%s [DONE %s] \n",
__func__, enable? "on":"off");
return ret;
}
/**
* Clear touch input events
*/
void mms_clear_input(struct mms_ts_info *info)
{
int i;
input_report_key(info->input_dev, BTN_TOUCH, 0);
input_report_key(info->input_dev, BTN_TOOL_FINGER, 0);
for (i = 0; i< MAX_FINGER_NUM; i++) {
info->finger_state[i] = 0;
input_mt_slot(info->input_dev, i);
input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, false);
}
info->touch_count = 0;
input_sync(info->input_dev);
return;
}
/**
* Input event handler - Report touch input event
*/
void mms_input_event_handler(struct mms_ts_info *info, u8 sz, u8 *buf)
{
struct i2c_client *client = info->client;
int i;
tsp_debug_dbg(false, &client->dev, "%s [START]\n", __func__);
tsp_debug_dbg(false, &client->dev, "%s - sz[%d] buf[0x%02X]\n", __func__, sz, buf[0]);
for (i = 1; i < sz; i += info->event_size) {
u8 *tmp = &buf[i];
int id = (tmp[0] & MIP_EVENT_INPUT_ID) - 1;
int x = tmp[2] | ((tmp[1] & 0xf) << 8);
int y = tmp[3] | (((tmp[1] >> 4) & 0xf) << 8);
int pressure = tmp[4];
//int size = tmp[5]; // sumsize
int touch_major = tmp[6];
int touch_minor = tmp[7];
int palm = (tmp[0] & MIP_EVENT_INPUT_PALM) >> 4;
// Report input data
#if MMS_USE_TOUCHKEY
if ((tmp[0] & MIP_EVENT_INPUT_SCREEN) == 0) {
//Touchkey Event
int key = tmp[0] & 0xf;
int key_state = (tmp[0] & MIP_EVENT_INPUT_PRESS) ? 1 : 0;
int key_code = 0;
//Report touchkey event
switch (key) {
case 1:
key_code = KEY_MENU;
//tsp_debug_dbg(true, &client->dev, "Key : KEY_MENU\n");
break;
case 2:
key_code = KEY_BACK;
//tsp_debug_dbg(true, &client->dev, "Key : KEY_BACK\n");
break;
default:
tsp_debug_err(true, &client->dev,
"%s [ERROR] Unknown key code [%d]\n",
__func__, key);
continue;
break;
}
input_report_key(info->input_dev, key_code, key_state);
tsp_debug_dbg(true, &client->dev, "%s - Key : ID[%d] Code[%d] State[%d]\n",
__func__, key, key_code, key_state);
} else
#endif
{
//Report touchscreen event
if ((tmp[0] & MIP_EVENT_INPUT_PRESS) == 0) {
//Release
input_mt_slot(info->input_dev, id);
#ifdef CONFIG_SEC_FACTORY
input_report_abs(info->input_dev, ABS_MT_PRESSURE, 0);
#endif
input_mt_report_slot_state(info->input_dev,
MT_TOOL_FINGER, false);
if (info->finger_state[id] != 0){
info->touch_count--;
if (!info->touch_count) {
input_report_key(info->input_dev, BTN_TOUCH, 0);
input_report_key(info->input_dev,
BTN_TOOL_FINGER, 0);
}
info->finger_state[id] = 0;
tsp_debug_dbg(true, &client->dev,
"R[%d] V[%02x%02x%02x] tc:%d\n",
id, info->boot_ver_ic, info->core_ver_ic,
info->config_ver_ic, info->touch_count);
}
continue;
}
//Press or Move
input_mt_slot(info->input_dev, id);
input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, true);
input_report_key(info->input_dev, BTN_TOUCH, 1);
input_report_key(info->input_dev, BTN_TOOL_FINGER, 1);
input_report_abs(info->input_dev, ABS_MT_POSITION_X, x);
input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y);
#ifdef CONFIG_SEC_FACTORY
if (pressure)
input_report_abs(info->input_dev, ABS_MT_PRESSURE, pressure);
else
input_report_abs(info->input_dev, ABS_MT_PRESSURE, 1);
#endif
input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, touch_major);
input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR, touch_minor);
input_report_abs(info->input_dev, ABS_MT_PALM, palm);
if (info->finger_state[id] == 0){
info->finger_state[id] = 1;
info->touch_count++;
#ifdef CONFIG_SAMSUNG_PRODUCT_SHIP
tsp_debug_info(true, &client->dev,
"P[%d] z:%d p:%d m:%d,%d tc:%d\n",
id, pressure, palm, touch_major, touch_minor, info->touch_count);
#else
tsp_debug_dbg(true, &client->dev,
"P[%d] (%d, %d) z:%d p:%d m:%d,%d tc:%d\n",
id, x, y, pressure, palm, touch_major, touch_minor, info->touch_count);
#endif
}
}
}
input_sync(info->input_dev);
tsp_debug_dbg(false, &client->dev, "%s [DONE]\n", __func__);
return;
}
#if MMS_USE_DEVICETREE
/**
* Parse device tree
*/
int mms_parse_devicetree(struct device *dev, struct mms_ts_info *info)
{
struct device_node *np = dev->of_node;
int ret;
tsp_debug_info(true, dev, "%s [START]\n", __func__);
ret = of_property_read_u32(np, "melfas,max_x", &info->dtdata->max_x);
if (ret) {
tsp_debug_err(true, dev, "%s [ERROR] max_x\n", __func__);
info->dtdata->max_x = 720;
}
ret = of_property_read_u32(np, "melfas,max_y", &info->dtdata->max_y);
if (ret) {
tsp_debug_err(true, dev, "%s [ERROR] max_y\n", __func__);
info->dtdata->max_y = 1280;
}
info->dtdata->gpio_intr = of_get_named_gpio(np, "melfas,irq-gpio", 0);
gpio_request(info->dtdata->gpio_intr, "irq-gpio");
gpio_direction_input(info->dtdata->gpio_intr);
info->client->irq = gpio_to_irq(info->dtdata->gpio_intr);
info->dtdata->gpio_scl = of_get_named_gpio(np, "melfas,scl-gpio", 0);
gpio_request(info->dtdata->gpio_scl, "melfas_scl_gpio");
info->dtdata->gpio_sda = of_get_named_gpio(np, "melfas,sda-gpio", 0);
gpio_request(info->dtdata->gpio_sda, "melfas_sda_gpio");
if (of_property_read_string(np, "melfas,vdd_en", &info->dtdata->gpio_vdd_en)) {
tsp_debug_err(true, dev, "Failed to get regulator_dvdd name property\n");
}
if (of_property_read_string(np, "melfas,io_en", &info->dtdata->gpio_io_en)) {
tsp_debug_err(true, dev, "Failed to get regulator_avdd name property\n");
info->dtdata->gpio_io_en = NULL;
}
if (of_property_read_string(np, "melfas,fw_name", &info->dtdata->fw_name)) {
tsp_debug_err(true, dev, "Failed to get fw_name property\n");
info->dtdata->fw_name = INTERNAL_FW_PATH;
}
tsp_debug_info(true, dev, "%s: fw_name %s max_x:%d max_y:%d int:%d irq:%d sda:%d scl:%d \n",
__func__, info->dtdata->fw_name, info->dtdata->max_x, info->dtdata->max_y,
info->dtdata->gpio_intr, info->client->irq, info->dtdata->gpio_sda,
info->dtdata->gpio_scl);
return 0;
}
#endif
/**
* Config input interface
*/
void mms_config_input(struct mms_ts_info *info)
{
struct input_dev *input_dev = info->input_dev;
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
//Screen
set_bit(EV_SYN, input_dev->evbit);
set_bit(EV_ABS, input_dev->evbit);
set_bit(BTN_TOUCH, input_dev->keybit);
set_bit(BTN_TOOL_FINGER, input_dev->keybit);
set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
input_mt_init_slots(input_dev, MAX_FINGER_NUM, INPUT_MT_DIRECT);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, info->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, info->max_y, 0, 0);
#ifdef CONFIG_SEC_FACTORY
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, INPUT_PRESSURE_MAX, 0, 0);
#endif
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, INPUT_TOUCH_MAJOR_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, INPUT_TOUCH_MINOR_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_MT_PALM, 0, 1, 0, 0);
//Key
set_bit(EV_KEY, input_dev->evbit);
#if MMS_USE_TOUCHKEY
set_bit(KEY_BACK, input_dev->keybit);
set_bit(KEY_MENU, input_dev->keybit);
#endif
#if MMS_USE_NAP_MODE
set_bit(EV_KEY, input_dev->evbit);
set_bit(KEY_POWER, input_dev->keybit);
#endif
tsp_debug_dbg(true, &info->client->dev, "%s [DONE]\n", __func__);
return;
}
#ifdef CONFIG_VBUS_NOTIFIER
int mms_vbus_notification(struct notifier_block *nb,
unsigned long cmd, void *data)
{
struct mms_ts_info *info = container_of(nb, struct mms_ts_info, vbus_nb);
vbus_status_t vbus_type = *(vbus_status_t *)data;
tsp_debug_info(true, &info->client->dev, "%s cmd=%lu, vbus_type=%d\n", __func__, cmd, vbus_type);
if (!info->enabled) {
tsp_debug_err(true, &info->client->dev, "%s tsp disabled",__func__);
return 0;
}
switch (vbus_type) {
case STATUS_VBUS_HIGH:
tsp_debug_info(true, &info->client->dev, "%s : attach\n",__func__);
info->ta_stsatus = true;
break;
case STATUS_VBUS_LOW:
tsp_debug_info(true, &info->client->dev, "%s : detach\n",__func__);
info->ta_stsatus = false;
break;
default:
break;
}
mms_charger_attached(info, info->ta_stsatus);
return 0;
}
#endif
/**
* Callback - get charger status
*/
#ifdef USE_TSP_TA_CALLBACKS
void mms_charger_status_cb(struct tsp_callbacks *cb, int status)
{
pr_info("%s: TA %s\n",
__func__, status ? "connected" : "disconnected");
if (status)
ta_connected = true;
else
ta_connected = false;
/* not yet defined functions */
}
void mms_register_callback(struct tsp_callbacks *cb)
{
charger_callbacks = cb;
pr_info("%s\n", __func__);
}
#endif

View file

@ -0,0 +1,136 @@
/*
* MELFAS MMS400 Touchscreen
*
* Copyright (C) 2014 MELFAS Inc.
*
*
* Protocol information
*
* Protocol Version : MIP 4.0
*
*/
#ifndef __MELFAS_MMS400_REG_H
#define __MELFAS_MMS400_REG_H
//Address
#define MIP_R0_INFO 0x01
#define MIP_R1_INFO_PRODUCT_NAME 0x00
#define MIP_R1_INFO_RESOLUTION_X 0x10
#define MIP_R1_INFO_RESOLUTION_Y 0x12
#define MIP_R1_INFO_NODE_NUM_X 0x14
#define MIP_R1_INFO_NODE_NUM_Y 0x15
#define MIP_R1_INFO_KEY_NUM 0x16
#define MIP_R1_INFO_VERSION_BOOT 0x20
#define MIP_R1_INFO_VERSION_CORE 0x22
#define MIP_R1_INFO_VERSION_CUSTOM 0x24
#define MIP_R1_INFO_VERSION_PARAM 0x26
#define MIP_R1_INFO_SECT_BOOT_START 0x30
#define MIP_R1_INFO_SECT_BOOT_END 0x31
#define MIP_R1_INFO_SECT_CORE_START 0x32
#define MIP_R1_INFO_SECT_CORE_END 0x33
#define MIP_R1_INFO_SECT_CUSTOM_START 0x34
#define MIP_R1_INFO_SECT_CUSTOM_END 0x35
#define MIP_R1_INFO_SECT_PARAM_START 0x36
#define MIP_R1_INFO_SECT_PARAM_END 0x37
#define MIP_R1_INFO_BUILD_DATE 0x40
#define MIP_R1_INFO_BUILD_TIME 0x44
#define MIP_R1_INFO_CHECKSUM_PRECALC 0x48
#define MIP_R1_INFO_CHECKSUM_REALTIME 0x4A
#define MIP_R1_INFO_CHECKSUM_CALC 0x4C
#define MIP_R1_INFO_PROTOCOL_NAME 0x50
#define MIP_R1_INFO_PROTOCOL_VERSION 0x58
#define MIP_R1_INFO_IC_ID 0x70
#define MIP_R0_EVENT 0x02
#define MIP_R1_EVENT_SUPPORTED_FUNC 0x00
#define MIP_R1_EVENT_FORMAT 0x04
#define MIP_R1_EVENT_SIZE 0x06
#define MIP_R1_EVENT_PACKET_INFO 0x10
#define MIP_R1_EVENT_PACKET_DATA 0x11
#define MIP_R0_CTRL 0x06
#define MIP_R1_CTRL_READY_STATUS 0x00
#define MIP_R1_CTRL_EVENT_READY 0x01
#define MIP_R1_CTRL_MODE 0x10
#define MIP_R1_CTRL_EVENT_TRIGGER_TYPE 0x11
#define MIP_R1_CTRL_RECALIBRATE 0x12
#define MIP_R1_CTRL_POWER_STATE 0x13
#define MIP_R1_CTRL_GESTURE_TYPE 0x14
#define MIP_R1_CTRL_DISABLE_ESD_ALERT 0x18
#define MIP_R1_CTRL_CHARGER_MODE 0x19
#define MIP_R1_CTRL_GLOVE_MODE 0x1A
#define MIP_R1_CTRL_WINDOW_MODE 0x1B
#define MIP_R1_CTRL_PALM_REJECTION 0x1C
#define MIP_R1_CTRL_DISABLE_EDGE_EXPAND 0x1D
#define MIP_R0_PARAM 0x08
#define MIP_R1_PARAM_BUFFER_ADDR 0x00
#define MIP_R1_PARAM_PROTOCOL 0x04
#define MIP_R1_PARAM_MODE 0x10
#define MIP_R0_TEST 0x0A
#define MIP_R1_TEST_BUF_ADDR 0x00
#define MIP_R1_TEST_PROTOCOL 0x02
#define MIP_R1_TEST_TYPE 0x10
#define MIP_R1_TEST_DATA_FORMAT 0x20
#define MIP_R1_TEST_ROW_NUM 0x20
#define MIP_R1_TEST_COL_NUM 0x21
#define MIP_R1_TEST_BUFFER_COL_NUM 0x22
#define MIP_R1_TEST_COL_AXIS 0x23
#define MIP_R1_TEST_KEY_NUM 0x24
#define MIP_R1_TEST_DATA_TYPE 0x25
#define MIP_R0_IMAGE 0x0C
#define MIP_R1_IMAGE_BUF_ADDR 0x00
#define MIP_R1_IMAGE_PROTOCOL_ID 0x04
#define MIP_R1_IMAGE_TYPE 0x10
#define MIP_R1_IMAGE_DATA_FORMAT 0x20
#define MIP_R1_IMAGE_ROW_NUM 0x20
#define MIP_R1_IMAGE_COL_NUM 0x21
#define MIP_R1_IMAGE_BUFFER_COL_NUM 0x22
#define MIP_R1_IMAGE_COL_AXIS 0x23
#define MIP_R1_IMAGE_KEY_NUM 0x24
#define MIP_R1_IMAGE_DATA_TYPE 0x25
#define MIP_R1_IMAGE_FINGER_NUM 0x30
#define MIP_R1_IMAGE_FINGER_AREA 0x31
#define MIP_R0_LOG 0x10
#define MIP_R1_LOG_TRIGGER 0x14
//Value
#define MIP_EVENT_INPUT_PRESS 0x80
#define MIP_EVENT_INPUT_SCREEN 0x40
#define MIP_EVENT_INPUT_HOVER 0x20
#define MIP_EVENT_INPUT_PALM 0x10
#define MIP_EVENT_INPUT_ID 0x0F
#define MIP_ALERT_ESD 1
#define MIP_ALERT_WAKEUP 2
#define MIP_CTRL_STATUS_NONE 0x05
#define MIP_CTRL_STATUS_READY 0xA0
#define MIP_CTRL_STATUS_LOG 0x77
#define MIP_CTRL_MODE_NORMAL 0
#define MIP_CTRL_MODE_PARAM 1
#define MIP_CTRL_MODE_TEST_CM 2
#define MIP_TEST_TYPE_NONE 0
#define MIP_TEST_TYPE_CM_DELTA 1
#define MIP_TEST_TYPE_CM_ABS 2
#define MIP_TEST_TYPE_CM_JITTER 3
#define MIP_TEST_TYPE_SHORT 4
#define MIP_IMG_TYPE_NONE 0
#define MIP_IMG_TYPE_INTENSITY 1
#define MIP_IMG_TYPE_RAWDATA 2
#define MIP_IMG_TYPE_WAIT 255
#define MIP_TRIGGER_TYPE_NONE 0
#define MIP_TRIGGER_TYPE_INTR 1
#define MIP_TRIGGER_TYPE_REG 2
#define MIP_LOG_MODE_NONE 0
#define MIP_LOG_MODE_TRIG 1
#endif /* __MELFAS_MMS400_REG_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,497 @@
/*
* MELFAS MMS438/449/458 Touchscreen
*
* Copyright (C) 2014 MELFAS Inc.
*
*
* Firmware update functions
*
*/
#include "melfas_mms400.h"
//ISC Info
#define ISC_PAGE_SIZE 128
//ISC Command
#define ISC_CMD_ERASE_ALL {0xFB,0x4A,0x00,0x15,0x00,0x00}
#define ISC_CMD_ERASE_PAGE {0xFB,0x4A,0x00,0x8F,0x00,0x00}
#define ISC_CMD_READ_PAGE {0xFB,0x4A,0x00,0xC2,0x00,0x00}
#define ISC_CMD_WRITE_PAGE {0xFB,0x4A,0x00,0xA5,0x00,0x00}
#define ISC_CMD_PROGRAM_PAGE {0xFB,0x4A,0x00,0x54,0x00,0x00}
#define ISC_CMD_READ_STATUS {0xFB,0x4A,0x36,0xC2,0x00,0x00}
#define ISC_CMD_EXIT {0xFB,0x4A,0x00,0x66,0x00,0x00}
//ISC Status
#define ISC_STATUS_BUSY 0x96
#define ISC_STATUS_DONE 0xAD
/**
* Read ISC status
*/
static int mms_isc_read_status(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
u8 cmd[6] = ISC_CMD_READ_STATUS;
u8 result = 0;
int cnt = 100;
int ret = 0;
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.flags = 0,
.buf = cmd,
.len = 6,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
.buf = &result,
.len = 1,
},
};
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
do {
if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg))!=ARRAY_SIZE(msg)) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] i2c_transfer\n", __func__);
return -1;
}
if (result == ISC_STATUS_DONE) {
ret = 0;
break;
} else if (result == ISC_STATUS_BUSY) {
ret = -1;
msleep(1);
} else {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] wrong value [0x%02X]\n",
__func__, result);
ret = -1;
msleep(1);
}
} while (--cnt);
if (!cnt) {
tsp_debug_err(true, &info->client->dev,
"%s [ERROR] count overflow - cnt [%d] status [0x%02X]\n",
__func__, cnt, result);
goto ERROR;
}
tsp_debug_dbg(true, &info->client->dev, "%s [DONE]\n", __func__);
return ret;
ERROR:
return ret;
}
/**
* Command : Erase Page
*/
static int mms_isc_erase_page(struct mms_ts_info *info, int offset)
{
u8 write_buf[6] =ISC_CMD_ERASE_PAGE;
struct i2c_msg msg[1] = {
{
.addr = info->client->addr,
.flags = 0,
.buf = write_buf,
.len = 6,
},
};
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
write_buf[4] = (u8)(((offset)>>8) & 0xFF);
write_buf[5] = (u8)(((offset)>>0) & 0xFF);
if (i2c_transfer(info->client->adapter, msg, ARRAY_SIZE(msg)) != ARRAY_SIZE(msg)) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] i2c_transfer\n", __func__);
goto ERROR;
}
if (mms_isc_read_status(info) != 0) {
goto ERROR;
}
tsp_debug_dbg(true, &info->client->dev, "%s [DONE] - Offset [0x%04X]\n", __func__, offset);
return 0;
ERROR:
return -1;
}
/**
* Command : Read Page
*/
static int mms_isc_read_page(struct mms_ts_info *info, int offset, u8 *data)
{
u8 write_buf[6] =ISC_CMD_READ_PAGE;
struct i2c_msg msg[2] = {
{
.addr = info->client->addr,
.flags = 0,
.buf = write_buf,
.len = 6,
}, {
.addr = info->client->addr,
.flags = I2C_M_RD,
.buf = data,
.len = ISC_PAGE_SIZE,
},
};
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
write_buf[4] = (u8)(((offset)>>8) & 0xFF);
write_buf[5] = (u8)(((offset)>>0) & 0xFF);
if (i2c_transfer(info->client->adapter, msg, ARRAY_SIZE(msg)) != ARRAY_SIZE(msg)) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] i2c_transfer\n", __func__);
goto ERROR;
}
tsp_debug_dbg(true, &info->client->dev, "%s [DONE] - Offset [0x%04X]\n", __func__, offset);
return 0;
ERROR:
return -1;
}
/**
* Command : Program Page
*/
static int mms_isc_program_page(struct mms_ts_info *info, int offset,
const u8 *data, int length)
{
u8 write_buf[134] = ISC_CMD_PROGRAM_PAGE;
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
if (length > 128) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] page length overflow\n", __func__);
goto ERROR;
}
write_buf[4] = (u8)(((offset)>>8) & 0xFF);
write_buf[5] = (u8)(((offset)>>0) & 0xFF);
memcpy(&write_buf[6], data, length);
if (i2c_master_send(info->client, write_buf, length+6 )!=length+6) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] i2c_master_send\n", __func__);
goto ERROR;
}
if (mms_isc_read_status(info) != 0) {
goto ERROR;
}
tsp_debug_dbg(true, &info->client->dev, "%s [DONE] - Offset[0x%04X] Length[%d]\n",
__func__, offset, length);
return 0;
ERROR:
return -1;
}
/**
* Command : Exit ISC
*/
static int mms_isc_exit(struct mms_ts_info *info)
{
u8 write_buf[6] = ISC_CMD_EXIT;
tsp_debug_dbg(true, &info->client->dev, "%s [START]\n", __func__);
if (i2c_master_send(info->client, write_buf, 6) != 6) {
tsp_debug_err(true, &info->client->dev, "%s [ERROR] i2c_master_send\n", __func__);
goto ERROR;
}
tsp_debug_dbg(true, &info->client->dev, "%s [DONE]\n", __func__);
return 0;
ERROR:
return -1;
}
/**
* Flash chip firmware (main function)
*/
int mms_flash_fw(struct mms_ts_info *info, const u8 *fw_data,
size_t fw_size, bool force, bool section)
{
struct mms_bin_hdr *fw_hdr;
struct mms_fw_img **img;
struct i2c_client *client = info->client;
int i;
int retires = 3;
int ret;
int nRet;
int nStartAddr;
int nWriteLength;
int nLast;
int nOffset;
int nTransferLength;
int size;
u8 *data;
u8 *cpydata;
int offset = sizeof(struct mms_bin_hdr);
bool update_flag = false;
bool update_flags[MMS_FW_MAX_SECT_NUM] = {false, };
u16 ver_chip[MMS_FW_MAX_SECT_NUM];
u16 ver_file[MMS_FW_MAX_SECT_NUM];
int offsetStart = 0;
u8 initData[ISC_PAGE_SIZE];
memset(initData, 0xFF, sizeof(initData));
tsp_debug_dbg(true, &client->dev, "%s [START]\n", __func__);
//Read firmware file
fw_hdr = (struct mms_bin_hdr *)fw_data;
img = vzalloc(sizeof(*img) * fw_hdr->section_num);
if (!img) {
tsp_debug_err(true, &client->dev, "Failed to img allocate memory\n");
nRet = -ENOMEM;
goto err_alloc_img;
}
//Check firmware file
if (memcmp(CHIP_FW_CODE, &fw_hdr->tag[4], 4)) {
tsp_debug_err(true, &client->dev, "%s [ERROR] F/W file is not for %s\n",
__func__, CHIP_NAME);
nRet = fw_err_file_type;
goto EXIT;
}
//Check chip firmware version
while (retires--) {
if (!mms_get_fw_version_u16(info, ver_chip))
break;
else
mms_reboot(info);
}
if (retires < 0) {
tsp_debug_err(true, &client->dev,
"%s [ERROR] cannot read chip firmware version\n",__func__);
memset(ver_chip, 0xFFFF, sizeof(ver_chip));
tsp_debug_dbg(true, &client->dev,
"%s - Chip firmware version is set to [0xFFFF]\n", __func__);
} else {
tsp_debug_info(true, &client->dev,
"%s - Chip firmware version [0x%04X 0x%04X 0x%04X 0x%04X]\n",
__func__, ver_chip[0], ver_chip[1], ver_chip[2], ver_chip[3]);
}
//Set update flag
tsp_debug_info(true, &client->dev,
"%s - Firmware file info : Sections[%d] Offset[0x%08X] Length[0x%08X]\n",
__func__, fw_hdr->section_num, fw_hdr->binary_offset, fw_hdr->binary_length);
for (i = 0; i < fw_hdr->section_num; i++, offset += sizeof(struct mms_fw_img)) {
img[i] = (struct mms_fw_img *)(fw_data + offset);
ver_file[i] = img[i]->version;
tsp_debug_dbg(true, &client->dev,
"%s - Section info : Section[%d] Version[0x%04X] StartPage[%d]"
" EndPage[%d] Offset[0x%08X] Length[0x%08X]\n",
__func__, i, img[i]->version, img[i]->start_page,
img[i]->end_page,img[i]->offset, img[i]->length);
tsp_debug_err(true, &client->dev,
"%s - Section[%d] IC: %04X / BIN: %04X\n",
__func__, i, ver_chip[i], ver_file[i]);
//Compare section version
if (ver_chip[i] < ver_file[i] || ver_chip[i] > ver_file[i] + 0x20) {
//Set update flag
update_flag = true;
update_flags[i] = true;
tsp_debug_info(true, &client->dev,
"%s - Section[%d] is need to be updated.", __func__, i);
}
}
//Set force update flag
if (force == true) {
update_flag = true;
update_flags[0] = true;
update_flags[1] = true;
update_flags[2] = true;
update_flags[3] = true;
tsp_debug_info(true, &client->dev, "%s - Force update\n", __func__);
}
//Exit when up-to-date
if (update_flag == false) {
nRet = fw_err_uptodate;
tsp_debug_dbg(true, &client->dev,
"%s [DONE] Chip firmware is already up-to-date\n", __func__);
goto EXIT;
}
//Set start addr offset
if (section == true) {
if (update_flags[0] == true) {
//boot
offsetStart = img[0]->start_page;
} else if (update_flags[1] == true) {
//core
offsetStart = img[1]->start_page;
} else if (update_flags[2] == true) {
//custom
offsetStart = img[2]->start_page;
} else if (update_flags[3] == true) {
//param
offsetStart = img[3]->start_page;
}
} else
offsetStart = 0;
offsetStart = offsetStart * 1024;
//Load firmware data
data = vzalloc(sizeof(u8) * fw_hdr->binary_length);
if (!data) {
tsp_debug_err(true, &client->dev, "Failed to data allocate memory\n");
nRet = -ENOMEM;
goto err_alloc_data;
}
size = fw_hdr->binary_length;
cpydata = vzalloc(ISC_PAGE_SIZE);
if (!cpydata) {
tsp_debug_err(true, &client->dev, "Failed to cpydata allocate memory\n");
nRet = -ENOMEM;
goto err_alloc_cpydata;
}
//Check firmware size
if (size % ISC_PAGE_SIZE !=0) {
size += ( ISC_PAGE_SIZE - (size % ISC_PAGE_SIZE) );
}
nStartAddr = 0;
nWriteLength = size;
nLast = nStartAddr + nWriteLength;
if ((nLast) % 8 != 0) {
nRet = fw_err_file_type;
tsp_debug_err(true, &client->dev, "%s [ERROR] Firmware size mismatch\n", __func__);
goto ERROR;
} else
memcpy(data,fw_data+fw_hdr->binary_offset,fw_hdr->binary_length);
//Set address
nOffset = nStartAddr + nWriteLength - ISC_PAGE_SIZE;
nTransferLength = ISC_PAGE_SIZE;
//Erase first page
tsp_debug_info(true, &client->dev, "%s - Erase first page : Offset[0x%04X]\n",
__func__, offsetStart);
nRet = mms_isc_erase_page(info, offsetStart);
if (nRet != 0) {
tsp_debug_err(true, &client->dev, "%s [ERROR] clear first page failed\n", __func__);
goto ERROR;
}
//Flash firmware
tsp_debug_info(true, &client->dev, "%s - Start Download : Offset Start[0x%04X] End[0x%04X]\n",
__func__, nOffset, offsetStart);
while( nOffset >= offsetStart )
{
tsp_debug_dbg(true, &client->dev, "%s - Downloading : Offset[0x%04X]\n", __func__, nOffset);
//Program (erase and write) a page
nRet = mms_isc_program_page(info, nOffset, &data[nOffset], nTransferLength);
if (nRet != 0) {
tsp_debug_err(true, &client->dev, "%s [ERROR] isc_program_page\n", __func__);
goto ERROR;
}
//Verify (read and compare)
if (mms_isc_read_page(info, nOffset, cpydata)) {
tsp_debug_err(true, &client->dev, "%s [ERROR] mms_isc_read_page\n", __func__);
goto ERROR;
}
if (memcmp(&data[nOffset], cpydata, ISC_PAGE_SIZE)) {
#if MMS_FW_UPDATE_DEBUG
print_hex_dump(KERN_ERR, "Firmware Page Write : ",
DUMP_PREFIX_OFFSET, 16, 1, data, ISC_PAGE_SIZE, false);
print_hex_dump(KERN_ERR, "Firmware Page Read : ",
DUMP_PREFIX_OFFSET, 16, 1, cpydata, ISC_PAGE_SIZE, false);
#endif
tsp_debug_err(true, &client->dev, "%s [ERROR] verify page failed\n", __func__);
ret = -1;
goto ERROR;
}
nOffset -= nTransferLength;
}
//Exit ISC
nRet = mms_isc_exit(info);
if (nRet != 0) {
tsp_debug_err(true, &client->dev, "%s [ERROR] mms_isc_exit\n", __func__);
goto ERROR;
}
//Reboot chip
mms_reboot(info);
//Check chip firmware version
if (mms_get_fw_version_u16(info, ver_chip)) {
tsp_debug_err(true, &client->dev,
"%s [ERROR] cannot read chip firmware version after flash\n", __func__);
nRet = -1;
goto ERROR;
} else {
for (i = 0; i < fw_hdr->section_num; i++) {
if (ver_chip[i] != ver_file[i]) {
tsp_debug_err(true, &client->dev,
"%s [ERROR] version mismatch after flash."
" Section[%d] : Chip[0x%04X] != File[0x%04X]\n",
__func__, i, ver_chip[i], ver_file[i]);
nRet = -1;
goto ERROR;
}
}
}
nRet = 0;
tsp_debug_dbg(true, &client->dev, "%s [DONE]\n", __func__);
goto DONE;
ERROR:
tsp_debug_err(true, &client->dev, "%s [ERROR]\n", __func__);
DONE:
vfree(cpydata);
err_alloc_cpydata:
vfree(data);
err_alloc_data:
EXIT:
vfree(img);
err_alloc_img:
return nRet;
}

View file

@ -0,0 +1,249 @@
/*
* Touch Screen driver for Renesas MIGO-R Platform
*
* Copyright (c) 2008 Magnus Damm
* Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com>,
* Kenati Technologies Pvt Ltd.
*
* This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This file 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/i2c.h>
#include <linux/timer.h>
#define EVENT_PENDOWN 1
#define EVENT_REPEAT 2
#define EVENT_PENUP 3
struct migor_ts_priv {
struct i2c_client *client;
struct input_dev *input;
int irq;
};
static const u_int8_t migor_ts_ena_seq[17] = { 0x33, 0x22, 0x11,
0x01, 0x06, 0x07, };
static const u_int8_t migor_ts_dis_seq[17] = { };
static irqreturn_t migor_ts_isr(int irq, void *dev_id)
{
struct migor_ts_priv *priv = dev_id;
unsigned short xpos, ypos;
unsigned char event;
u_int8_t buf[16];
/*
* The touch screen controller chip is hooked up to the CPU
* using I2C and a single interrupt line. The interrupt line
* is pulled low whenever someone taps the screen. To deassert
* the interrupt line we need to acknowledge the interrupt by
* communicating with the controller over the slow i2c bus.
*
* Since I2C bus controller may sleep we are using threaded
* IRQ here.
*/
memset(buf, 0, sizeof(buf));
/* Set Index 0 */
buf[0] = 0;
if (i2c_master_send(priv->client, buf, 1) != 1) {
dev_err(&priv->client->dev, "Unable to write i2c index\n");
goto out;
}
/* Now do Page Read */
if (i2c_master_recv(priv->client, buf, sizeof(buf)) != sizeof(buf)) {
dev_err(&priv->client->dev, "Unable to read i2c page\n");
goto out;
}
ypos = ((buf[9] & 0x03) << 8 | buf[8]);
xpos = ((buf[11] & 0x03) << 8 | buf[10]);
event = buf[12];
switch (event) {
case EVENT_PENDOWN:
case EVENT_REPEAT:
input_report_key(priv->input, BTN_TOUCH, 1);
input_report_abs(priv->input, ABS_X, ypos); /*X-Y swap*/
input_report_abs(priv->input, ABS_Y, xpos);
input_sync(priv->input);
break;
case EVENT_PENUP:
input_report_key(priv->input, BTN_TOUCH, 0);
input_sync(priv->input);
break;
}
out:
return IRQ_HANDLED;
}
static int migor_ts_open(struct input_dev *dev)
{
struct migor_ts_priv *priv = input_get_drvdata(dev);
struct i2c_client *client = priv->client;
int count;
/* enable controller */
count = i2c_master_send(client, migor_ts_ena_seq,
sizeof(migor_ts_ena_seq));
if (count != sizeof(migor_ts_ena_seq)) {
dev_err(&client->dev, "Unable to enable touchscreen.\n");
return -ENXIO;
}
return 0;
}
static void migor_ts_close(struct input_dev *dev)
{
struct migor_ts_priv *priv = input_get_drvdata(dev);
struct i2c_client *client = priv->client;
disable_irq(priv->irq);
/* disable controller */
i2c_master_send(client, migor_ts_dis_seq, sizeof(migor_ts_dis_seq));
enable_irq(priv->irq);
}
static int migor_ts_probe(struct i2c_client *client,
const struct i2c_device_id *idp)
{
struct migor_ts_priv *priv;
struct input_dev *input;
int error;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
input = input_allocate_device();
if (!priv || !input) {
dev_err(&client->dev, "failed to allocate memory\n");
error = -ENOMEM;
goto err_free_mem;
}
priv->client = client;
priv->input = input;
priv->irq = client->irq;
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
__set_bit(BTN_TOUCH, input->keybit);
input_set_abs_params(input, ABS_X, 95, 955, 0, 0);
input_set_abs_params(input, ABS_Y, 85, 935, 0, 0);
input->name = client->name;
input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev;
input->open = migor_ts_open;
input->close = migor_ts_close;
input_set_drvdata(input, priv);
error = request_threaded_irq(priv->irq, NULL, migor_ts_isr,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
client->name, priv);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
goto err_free_mem;
}
error = input_register_device(input);
if (error)
goto err_free_irq;
i2c_set_clientdata(client, priv);
device_init_wakeup(&client->dev, 1);
return 0;
err_free_irq:
free_irq(priv->irq, priv);
err_free_mem:
input_free_device(input);
kfree(priv);
return error;
}
static int migor_ts_remove(struct i2c_client *client)
{
struct migor_ts_priv *priv = i2c_get_clientdata(client);
free_irq(priv->irq, priv);
input_unregister_device(priv->input);
kfree(priv);
dev_set_drvdata(&client->dev, NULL);
return 0;
}
static int migor_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
enable_irq_wake(priv->irq);
return 0;
}
static int migor_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
disable_irq_wake(priv->irq);
return 0;
}
static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
static const struct i2c_device_id migor_ts_id[] = {
{ "migor_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, migor_ts);
static struct i2c_driver migor_ts_driver = {
.driver = {
.name = "migor_ts",
.pm = &migor_ts_pm,
},
.probe = migor_ts_probe,
.remove = migor_ts_remove,
.id_table = migor_ts_id,
};
module_i2c_driver(migor_ts_driver);
MODULE_DESCRIPTION("MigoR Touchscreen driver");
MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,219 @@
/*
* ICS MK712 touchscreen controller driver
*
* Copyright (c) 1999-2002 Transmeta Corporation
* Copyright (c) 2005 Rick Koch <n1gp@hotmail.com>
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
*/
/*
* 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.
*/
/*
* This driver supports the ICS MicroClock MK712 TouchScreen controller,
* found in Gateway AOL Connected Touchpad computers.
*
* Documentation for ICS MK712 can be found at:
* http://www.idt.com/products/getDoc.cfm?docID=18713923
*/
/*
* 1999-12-18: original version, Daniel Quinlan
* 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll
* to use queue_empty, Nathan Laredo
* 1999-12-20: improved random point rejection, Nathan Laredo
* 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed
* queue code, added module options, other fixes, Daniel Quinlan
* 2002-03-15: Clean up for kernel merge <alan@redhat.com>
* Fixed multi open race, fixed memory checks, fixed resource
* allocation, fixed close/powerdown bug, switched to new init
* 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch
* 2005-02-05: Rewritten for the input layer, Vojtech Pavlik
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <asm/io.h>
MODULE_AUTHOR("Daniel Quinlan <quinlan@pathname.com>, Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");
MODULE_LICENSE("GPL");
static unsigned int mk712_io = 0x260; /* Also 0x200, 0x208, 0x300 */
module_param_named(io, mk712_io, uint, 0);
MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
static unsigned int mk712_irq = 10; /* Also 12, 14, 15 */
module_param_named(irq, mk712_irq, uint, 0);
MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
/* eight 8-bit registers */
#define MK712_STATUS 0
#define MK712_X 2
#define MK712_Y 4
#define MK712_CONTROL 6
#define MK712_RATE 7
/* status */
#define MK712_STATUS_TOUCH 0x10
#define MK712_CONVERSION_COMPLETE 0x80
/* control */
#define MK712_ENABLE_INT 0x01
#define MK712_INT_ON_CONVERSION_COMPLETE 0x02
#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS 0x04
#define MK712_ENABLE_PERIODIC_CONVERSIONS 0x10
#define MK712_READ_ONE_POINT 0x20
#define MK712_POWERUP 0x40
static struct input_dev *mk712_dev;
static DEFINE_SPINLOCK(mk712_lock);
static irqreturn_t mk712_interrupt(int irq, void *dev_id)
{
unsigned char status;
static int debounce = 1;
static unsigned short last_x;
static unsigned short last_y;
spin_lock(&mk712_lock);
status = inb(mk712_io + MK712_STATUS);
if (~status & MK712_CONVERSION_COMPLETE) {
debounce = 1;
goto end;
}
if (~status & MK712_STATUS_TOUCH) {
debounce = 1;
input_report_key(mk712_dev, BTN_TOUCH, 0);
goto end;
}
if (debounce) {
debounce = 0;
goto end;
}
input_report_key(mk712_dev, BTN_TOUCH, 1);
input_report_abs(mk712_dev, ABS_X, last_x);
input_report_abs(mk712_dev, ABS_Y, last_y);
end:
last_x = inw(mk712_io + MK712_X) & 0x0fff;
last_y = inw(mk712_io + MK712_Y) & 0x0fff;
input_sync(mk712_dev);
spin_unlock(&mk712_lock);
return IRQ_HANDLED;
}
static int mk712_open(struct input_dev *dev)
{
unsigned long flags;
spin_lock_irqsave(&mk712_lock, flags);
outb(0, mk712_io + MK712_CONTROL); /* Reset */
outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
MK712_ENABLE_PERIODIC_CONVERSIONS |
MK712_POWERUP, mk712_io + MK712_CONTROL);
outb(10, mk712_io + MK712_RATE); /* 187 points per second */
spin_unlock_irqrestore(&mk712_lock, flags);
return 0;
}
static void mk712_close(struct input_dev *dev)
{
unsigned long flags;
spin_lock_irqsave(&mk712_lock, flags);
outb(0, mk712_io + MK712_CONTROL);
spin_unlock_irqrestore(&mk712_lock, flags);
}
static int __init mk712_init(void)
{
int err;
if (!request_region(mk712_io, 8, "mk712")) {
printk(KERN_WARNING "mk712: unable to get IO region\n");
return -ENODEV;
}
outb(0, mk712_io + MK712_CONTROL);
if ((inw(mk712_io + MK712_X) & 0xf000) || /* Sanity check */
(inw(mk712_io + MK712_Y) & 0xf000) ||
(inw(mk712_io + MK712_STATUS) & 0xf333)) {
printk(KERN_WARNING "mk712: device not present\n");
err = -ENODEV;
goto fail1;
}
mk712_dev = input_allocate_device();
if (!mk712_dev) {
printk(KERN_ERR "mk712: not enough memory\n");
err = -ENOMEM;
goto fail1;
}
mk712_dev->name = "ICS MicroClock MK712 TouchScreen";
mk712_dev->phys = "isa0260/input0";
mk712_dev->id.bustype = BUS_ISA;
mk712_dev->id.vendor = 0x0005;
mk712_dev->id.product = 0x0001;
mk712_dev->id.version = 0x0100;
mk712_dev->open = mk712_open;
mk712_dev->close = mk712_close;
mk712_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
mk712_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0);
input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0);
if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) {
printk(KERN_WARNING "mk712: unable to get IRQ\n");
err = -EBUSY;
goto fail1;
}
err = input_register_device(mk712_dev);
if (err)
goto fail2;
return 0;
fail2: free_irq(mk712_irq, mk712_dev);
fail1: input_free_device(mk712_dev);
release_region(mk712_io, 8);
return err;
}
static void __exit mk712_exit(void)
{
input_unregister_device(mk712_dev);
free_irq(mk712_irq, mk712_dev);
release_region(mk712_io, 8);
}
module_init(mk712_init);
module_exit(mk712_exit);

View file

@ -0,0 +1,595 @@
/*
* Copyright (C) 2012 Samsung Electronics Co.Ltd
* Author: Joonyoung Shim <jy0922.shim@samsung.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/module.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/i2c.h>
#include <linux/i2c/mms114.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
/* Write only registers */
#define MMS114_MODE_CONTROL 0x01
#define MMS114_OPERATION_MODE_MASK 0xE
#define MMS114_ACTIVE (1 << 1)
#define MMS114_XY_RESOLUTION_H 0x02
#define MMS114_X_RESOLUTION 0x03
#define MMS114_Y_RESOLUTION 0x04
#define MMS114_CONTACT_THRESHOLD 0x05
#define MMS114_MOVING_THRESHOLD 0x06
/* Read only registers */
#define MMS114_PACKET_SIZE 0x0F
#define MMS114_INFOMATION 0x10
#define MMS114_TSP_REV 0xF0
/* Minimum delay time is 50us between stop and start signal of i2c */
#define MMS114_I2C_DELAY 50
/* 200ms needs after power on */
#define MMS114_POWERON_DELAY 200
/* Touchscreen absolute values */
#define MMS114_MAX_AREA 0xff
#define MMS114_MAX_TOUCH 10
#define MMS114_PACKET_NUM 8
/* Touch type */
#define MMS114_TYPE_NONE 0
#define MMS114_TYPE_TOUCHSCREEN 1
#define MMS114_TYPE_TOUCHKEY 2
struct mms114_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct regulator *core_reg;
struct regulator *io_reg;
const struct mms114_platform_data *pdata;
/* Use cache data for mode control register(write only) */
u8 cache_mode_control;
};
struct mms114_touch {
u8 id:4, reserved_bit4:1, type:2, pressed:1;
u8 x_hi:4, y_hi:4;
u8 x_lo;
u8 y_lo;
u8 width;
u8 strength;
u8 reserved[2];
} __packed;
static int __mms114_read_reg(struct mms114_data *data, unsigned int reg,
unsigned int len, u8 *val)
{
struct i2c_client *client = data->client;
struct i2c_msg xfer[2];
u8 buf = reg & 0xff;
int error;
if (reg <= MMS114_MODE_CONTROL && reg + len > MMS114_MODE_CONTROL)
BUG();
/* Write register: use repeated start */
xfer[0].addr = client->addr;
xfer[0].flags = I2C_M_TEN | I2C_M_NOSTART;
xfer[0].len = 1;
xfer[0].buf = &buf;
/* Read data */
xfer[1].addr = client->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = len;
xfer[1].buf = val;
error = i2c_transfer(client->adapter, xfer, 2);
if (error != 2) {
dev_err(&client->dev,
"%s: i2c transfer failed (%d)\n", __func__, error);
return error < 0 ? error : -EIO;
}
udelay(MMS114_I2C_DELAY);
return 0;
}
static int mms114_read_reg(struct mms114_data *data, unsigned int reg)
{
u8 val;
int error;
if (reg == MMS114_MODE_CONTROL)
return data->cache_mode_control;
error = __mms114_read_reg(data, reg, 1, &val);
return error < 0 ? error : val;
}
static int mms114_write_reg(struct mms114_data *data, unsigned int reg,
unsigned int val)
{
struct i2c_client *client = data->client;
u8 buf[2];
int error;
buf[0] = reg & 0xff;
buf[1] = val & 0xff;
error = i2c_master_send(client, buf, 2);
if (error != 2) {
dev_err(&client->dev,
"%s: i2c send failed (%d)\n", __func__, error);
return error < 0 ? error : -EIO;
}
udelay(MMS114_I2C_DELAY);
if (reg == MMS114_MODE_CONTROL)
data->cache_mode_control = val;
return 0;
}
static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *touch)
{
const struct mms114_platform_data *pdata = data->pdata;
struct i2c_client *client = data->client;
struct input_dev *input_dev = data->input_dev;
unsigned int id;
unsigned int x;
unsigned int y;
if (touch->id > MMS114_MAX_TOUCH) {
dev_err(&client->dev, "Wrong touch id (%d)\n", touch->id);
return;
}
if (touch->type != MMS114_TYPE_TOUCHSCREEN) {
dev_err(&client->dev, "Wrong touch type (%d)\n", touch->type);
return;
}
id = touch->id - 1;
x = touch->x_lo | touch->x_hi << 8;
y = touch->y_lo | touch->y_hi << 8;
if (x > pdata->x_size || y > pdata->y_size) {
dev_dbg(&client->dev,
"Wrong touch coordinates (%d, %d)\n", x, y);
return;
}
if (pdata->x_invert)
x = pdata->x_size - x;
if (pdata->y_invert)
y = pdata->y_size - y;
dev_dbg(&client->dev,
"id: %d, type: %d, pressed: %d, x: %d, y: %d, width: %d, strength: %d\n",
id, touch->type, touch->pressed,
x, y, touch->width, touch->strength);
input_mt_slot(input_dev, id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, touch->pressed);
if (touch->pressed) {
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, touch->width);
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
input_report_abs(input_dev, ABS_MT_PRESSURE, touch->strength);
}
}
static irqreturn_t mms114_interrupt(int irq, void *dev_id)
{
struct mms114_data *data = dev_id;
struct input_dev *input_dev = data->input_dev;
struct mms114_touch touch[MMS114_MAX_TOUCH];
int packet_size;
int touch_size;
int index;
int error;
mutex_lock(&input_dev->mutex);
if (!input_dev->users) {
mutex_unlock(&input_dev->mutex);
goto out;
}
mutex_unlock(&input_dev->mutex);
packet_size = mms114_read_reg(data, MMS114_PACKET_SIZE);
if (packet_size <= 0)
goto out;
touch_size = packet_size / MMS114_PACKET_NUM;
error = __mms114_read_reg(data, MMS114_INFOMATION, packet_size,
(u8 *)touch);
if (error < 0)
goto out;
for (index = 0; index < touch_size; index++)
mms114_process_mt(data, touch + index);
input_mt_report_pointer_emulation(data->input_dev, true);
input_sync(data->input_dev);
out:
return IRQ_HANDLED;
}
static int mms114_set_active(struct mms114_data *data, bool active)
{
int val;
val = mms114_read_reg(data, MMS114_MODE_CONTROL);
if (val < 0)
return val;
val &= ~MMS114_OPERATION_MODE_MASK;
/* If active is false, sleep mode */
if (active)
val |= MMS114_ACTIVE;
return mms114_write_reg(data, MMS114_MODE_CONTROL, val);
}
static int mms114_get_version(struct mms114_data *data)
{
struct device *dev = &data->client->dev;
u8 buf[6];
int error;
error = __mms114_read_reg(data, MMS114_TSP_REV, 6, buf);
if (error < 0)
return error;
dev_info(dev, "TSP Rev: 0x%x, HW Rev: 0x%x, Firmware Ver: 0x%x\n",
buf[0], buf[1], buf[3]);
return 0;
}
static int mms114_setup_regs(struct mms114_data *data)
{
const struct mms114_platform_data *pdata = data->pdata;
int val;
int error;
error = mms114_get_version(data);
if (error < 0)
return error;
error = mms114_set_active(data, true);
if (error < 0)
return error;
val = (pdata->x_size >> 8) & 0xf;
val |= ((pdata->y_size >> 8) & 0xf) << 4;
error = mms114_write_reg(data, MMS114_XY_RESOLUTION_H, val);
if (error < 0)
return error;
val = pdata->x_size & 0xff;
error = mms114_write_reg(data, MMS114_X_RESOLUTION, val);
if (error < 0)
return error;
val = pdata->y_size & 0xff;
error = mms114_write_reg(data, MMS114_Y_RESOLUTION, val);
if (error < 0)
return error;
if (pdata->contact_threshold) {
error = mms114_write_reg(data, MMS114_CONTACT_THRESHOLD,
pdata->contact_threshold);
if (error < 0)
return error;
}
if (pdata->moving_threshold) {
error = mms114_write_reg(data, MMS114_MOVING_THRESHOLD,
pdata->moving_threshold);
if (error < 0)
return error;
}
return 0;
}
static int mms114_start(struct mms114_data *data)
{
struct i2c_client *client = data->client;
int error;
error = regulator_enable(data->core_reg);
if (error) {
dev_err(&client->dev, "Failed to enable avdd: %d\n", error);
return error;
}
error = regulator_enable(data->io_reg);
if (error) {
dev_err(&client->dev, "Failed to enable vdd: %d\n", error);
regulator_disable(data->core_reg);
return error;
}
mdelay(MMS114_POWERON_DELAY);
error = mms114_setup_regs(data);
if (error < 0) {
regulator_disable(data->io_reg);
regulator_disable(data->core_reg);
return error;
}
if (data->pdata->cfg_pin)
data->pdata->cfg_pin(true);
enable_irq(client->irq);
return 0;
}
static void mms114_stop(struct mms114_data *data)
{
struct i2c_client *client = data->client;
int error;
disable_irq(client->irq);
if (data->pdata->cfg_pin)
data->pdata->cfg_pin(false);
error = regulator_disable(data->io_reg);
if (error)
dev_warn(&client->dev, "Failed to disable vdd: %d\n", error);
error = regulator_disable(data->core_reg);
if (error)
dev_warn(&client->dev, "Failed to disable avdd: %d\n", error);
}
static int mms114_input_open(struct input_dev *dev)
{
struct mms114_data *data = input_get_drvdata(dev);
return mms114_start(data);
}
static void mms114_input_close(struct input_dev *dev)
{
struct mms114_data *data = input_get_drvdata(dev);
mms114_stop(data);
}
#ifdef CONFIG_OF
static struct mms114_platform_data *mms114_parse_dt(struct device *dev)
{
struct mms114_platform_data *pdata;
struct device_node *np = dev->of_node;
if (!np)
return NULL;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "failed to allocate platform data\n");
return NULL;
}
if (of_property_read_u32(np, "x-size", &pdata->x_size)) {
dev_err(dev, "failed to get x-size property\n");
return NULL;
};
if (of_property_read_u32(np, "y-size", &pdata->y_size)) {
dev_err(dev, "failed to get y-size property\n");
return NULL;
};
of_property_read_u32(np, "contact-threshold",
&pdata->contact_threshold);
of_property_read_u32(np, "moving-threshold",
&pdata->moving_threshold);
if (of_find_property(np, "x-invert", NULL))
pdata->x_invert = true;
if (of_find_property(np, "y-invert", NULL))
pdata->y_invert = true;
return pdata;
}
#else
static inline struct mms114_platform_data *mms114_parse_dt(struct device *dev)
{
return NULL;
}
#endif
static int mms114_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct mms114_platform_data *pdata;
struct mms114_data *data;
struct input_dev *input_dev;
int error;
pdata = dev_get_platdata(&client->dev);
if (!pdata)
pdata = mms114_parse_dt(&client->dev);
if (!pdata) {
dev_err(&client->dev, "Need platform data\n");
return -EINVAL;
}
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_PROTOCOL_MANGLING)) {
dev_err(&client->dev,
"Need i2c bus that supports protocol mangling\n");
return -ENODEV;
}
data = devm_kzalloc(&client->dev, sizeof(struct mms114_data),
GFP_KERNEL);
input_dev = devm_input_allocate_device(&client->dev);
if (!data || !input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
data->client = client;
data->input_dev = input_dev;
data->pdata = pdata;
input_dev->name = "MELFAS MMS114 Touchscreen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
input_dev->open = mms114_input_open;
input_dev->close = mms114_input_close;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, 0, data->pdata->x_size, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, data->pdata->y_size, 0, 0);
/* For multi touch */
input_mt_init_slots(input_dev, MMS114_MAX_TOUCH, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, MMS114_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, data->pdata->x_size, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, data->pdata->y_size, 0, 0);
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
input_set_drvdata(input_dev, data);
i2c_set_clientdata(client, data);
data->core_reg = devm_regulator_get(&client->dev, "avdd");
if (IS_ERR(data->core_reg)) {
error = PTR_ERR(data->core_reg);
dev_err(&client->dev,
"Unable to get the Core regulator (%d)\n", error);
return error;
}
data->io_reg = devm_regulator_get(&client->dev, "vdd");
if (IS_ERR(data->io_reg)) {
error = PTR_ERR(data->io_reg);
dev_err(&client->dev,
"Unable to get the IO regulator (%d)\n", error);
return error;
}
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
mms114_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
dev_name(&client->dev), data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
return error;
}
disable_irq(client->irq);
error = input_register_device(data->input_dev);
if (error) {
dev_err(&client->dev, "Failed to register input device\n");
return error;
}
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int mms114_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mms114_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;
int id;
/* Release all touch */
for (id = 0; id < MMS114_MAX_TOUCH; id++) {
input_mt_slot(input_dev, id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
}
input_mt_report_pointer_emulation(input_dev, true);
input_sync(input_dev);
mutex_lock(&input_dev->mutex);
if (input_dev->users)
mms114_stop(data);
mutex_unlock(&input_dev->mutex);
return 0;
}
static int mms114_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mms114_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;
int error;
mutex_lock(&input_dev->mutex);
if (input_dev->users) {
error = mms114_start(data);
if (error < 0) {
mutex_unlock(&input_dev->mutex);
return error;
}
}
mutex_unlock(&input_dev->mutex);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume);
static const struct i2c_device_id mms114_id[] = {
{ "mms114", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mms114_id);
#ifdef CONFIG_OF
static const struct of_device_id mms114_dt_match[] = {
{ .compatible = "melfas,mms114" },
{ }
};
#endif
static struct i2c_driver mms114_driver = {
.driver = {
.name = "mms114",
.owner = THIS_MODULE,
.pm = &mms114_pm_ops,
.of_match_table = of_match_ptr(mms114_dt_match),
},
.probe = mms114_probe,
.id_table = mms114_id,
};
module_i2c_driver(mms114_driver);
/* Module information */
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
MODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver");
MODULE_LICENSE("GPL");

Some files were not shown because too many files have changed in this diff Show more