/*
* ADS7846 based touchscreen and sensor driver
*
* 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
*
* 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/hwmon.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <asm/irq.h>
/*
* This code has been heavily tested on a Nokia 770, and lightly
* tested on other ads7846 devices (OSK/Mistral, Lubbock).
* TSC2046 is just newer ads7846 silicon.
* Support for ads7843 tested on Atmel at91sam926x-EK.
* Support for ads7845 has only been stubbed in.
*
* IRQ handling needs a workaround because of a shortcoming in handling
* edge triggered IRQs on some platforms like the OMAP1/2. These
* platforms don't handle the ARM lazy IRQ disabling properly, thus we
* have to maintain our own SW IRQ disabled status. This should be
* removed as soon as the affected platform's IRQ handling is fixed.
*
* app note sbaa036 talks in more detail about accurate sampling...
* that ought to help in situations like LCDs inducing noise (which
* can also be helped by using synch signals) and more generally.
* This driver tries to utilize the measures described in the app
* note. The strength of filtering can be set in the board-* specific
* files.
*/
#define TS_POLL_DELAY (1 * 1000000) /* ns delay before the first sample */
#define TS_POLL_PERIOD (5 * 1000000) /* ns delay between samples */
/* this driver doesn't aim at the peak continuous sample rate */
#define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
struct ts_event {
/* For portability, we can't read 12 bit values using SPI (which
* would make the controller deliver them as native byteorder u16
* with msbs zeroed). Instead, we read them as two 8-bit values,
* *** WHICH NEED BYTESWAPPING *** and range adjustment.
*/
u16 x;
u16 y;
u16 z1, z2;
int ignore;
};
struct ads7846 {
struct input_dev *input;
char phys[32];
struct spi_device *spi;
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
struct attribute_group *attr_group;
struct device *hwmon;
#endif
u16 model;
u16 vref_mv;
u16 vref_delay_usecs;
u16 x_plate_ohms;
u16 pressure_max;
u8 read_x, read_y, read_z1, read_z2, pwrdown;
u16 dummy; /* for the pwrdown read */
struct ts_event tc;
struct spi_transfer xfer[18];
struct spi_message msg[5];
struct spi_message *last_msg;
int msg_idx;
int read_cnt;
int read_rep;
int last_read;
u16 debounce_max;
u16 debounce_tol;
u16 debounce_rep;
u16 penirq_recheck_delay_usecs;
spinlock_t lock;
struct hrtimer timer;
unsigned pendown:1; /* P: lock */
unsigned pending:1; /* P: lock */
// FIXME remove "irq_disabled"
unsigned irq_disabled:1; /* P: lock */
unsigned disabled:1;
unsigned is_suspended:1;
int (*filter)(void *data, int data_idx, int *val);
void *filter_data;
void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void);
};
/* leave chip selected when we're done, for quicker re-select? */
#if 0
#define CS_CHANGE(xfer) ((xfer).cs_change = 1)
#else
#define CS_CHANGE(xfer) ((xfer).cs_change = 0)
#endif
/*--------------------------------------------------------------------------*/
/* The ADS7846 has touchscreen and other sensors.
* Earlier ads784x chips are somewhat compatible.
*/
#define ADS_START (1 << 7)
#define ADS_A2A1A0_d_y (1 << 4) /* differential */
#define ADS_A2A1A0_d_z1 (3 << 4) /* differential */
#define ADS_A2A1A0_d_z2 (4 << 4) /* differential */
#define ADS_A2A1A0_d_x (5 << 4) /* differential */
#define ADS_A2A1A0_temp0 (0 << 4) /* non-differential */
#define ADS_A2A1A0_vbatt (2 << 4) /* non-differential */
#define ADS_A2A1A0_vaux (6 << 4) /* non-differential */
#define ADS_A2A1A0_temp1 (7 << 4) /* non-differential */
#define ADS_8_BIT (1 << 3)
#define ADS_12_BIT (0 << 3)
#define ADS_SER (1 << 2) /* non-differential */
#define ADS_DFR (0 << 2) /* differential */
#define ADS_PD10_PDOWN (0 << 0) /* lowpower mode + penirq */
#define ADS_PD10_ADC_ON (1 << 0) /* ADC on */
#define ADS_PD10_REF_ON (2 << 0) /* vREF on + penirq */
#define ADS_PD10_ALL_ON (3 << 0) /* ADC + vREF on */
#define MAX_12BIT ((1<<12)-1)
/* leave ADC powered up (disables penirq) between differential samples */
#define READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \
| ADS_12_BIT | ADS_DFR | \
(adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref))
#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref))
#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref))
#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref))
#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */
/* single-ended samples need to first power up reference voltage;
* we leave both ADC and VREF powered
*/
#define READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
| ADS_12_BIT | ADS_SER)
#define REF_ON (READ_12BIT_DFR(x, 1, 1))
#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
/*--------------------------------------------------------------------------*/
/*
* Non-touchscreen sensors o