forked from Minki/linux
Input: tsc2005 - convert to regmap
Convert driver so that it uses regmap instead of directly using spi_transfer for all register accesses. Signed-off-by: Sebastian Reichel <sre@kernel.org> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
f00d1f8f1d
commit
273cf48aa9
@ -917,6 +917,7 @@ config TOUCHSCREEN_TSC_SERIO
|
|||||||
config TOUCHSCREEN_TSC2005
|
config TOUCHSCREEN_TSC2005
|
||||||
tristate "TSC2005 based touchscreens"
|
tristate "TSC2005 based touchscreens"
|
||||||
depends on SPI_MASTER
|
depends on SPI_MASTER
|
||||||
|
select REGMAP_SPI
|
||||||
help
|
help
|
||||||
Say Y here if you have a TSC2005 based touchscreen.
|
Say Y here if you have a TSC2005 based touchscreen.
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/spi/tsc2005.h>
|
#include <linux/spi/tsc2005.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The touchscreen interface operates as follows:
|
* The touchscreen interface operates as follows:
|
||||||
@ -120,20 +121,37 @@
|
|||||||
#define TSC2005_SPI_MAX_SPEED_HZ 10000000
|
#define TSC2005_SPI_MAX_SPEED_HZ 10000000
|
||||||
#define TSC2005_PENUP_TIME_MS 40
|
#define TSC2005_PENUP_TIME_MS 40
|
||||||
|
|
||||||
struct tsc2005_spi_rd {
|
static const struct regmap_range tsc2005_writable_ranges[] = {
|
||||||
struct spi_transfer spi_xfer;
|
regmap_reg_range(TSC2005_REG_AUX_HIGH, TSC2005_REG_CFR2),
|
||||||
u32 spi_tx;
|
|
||||||
u32 spi_rx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct regmap_access_table tsc2005_writable_table = {
|
||||||
|
.yes_ranges = tsc2005_writable_ranges,
|
||||||
|
.n_yes_ranges = ARRAY_SIZE(tsc2005_writable_ranges),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct regmap_config tsc2005_regmap_config = {
|
||||||
|
.reg_bits = 8,
|
||||||
|
.val_bits = 16,
|
||||||
|
.reg_stride = 0x08,
|
||||||
|
.max_register = 0x78,
|
||||||
|
.read_flag_mask = TSC2005_REG_READ,
|
||||||
|
.write_flag_mask = TSC2005_REG_PND0,
|
||||||
|
.wr_table = &tsc2005_writable_table,
|
||||||
|
.use_single_rw = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tsc2005_data {
|
||||||
|
u16 x;
|
||||||
|
u16 y;
|
||||||
|
u16 z1;
|
||||||
|
u16 z2;
|
||||||
|
} __packed;
|
||||||
|
#define TSC2005_DATA_REGS 4
|
||||||
|
|
||||||
struct tsc2005 {
|
struct tsc2005 {
|
||||||
struct spi_device *spi;
|
struct spi_device *spi;
|
||||||
|
struct regmap *regmap;
|
||||||
struct spi_message spi_read_msg;
|
|
||||||
struct tsc2005_spi_rd spi_x;
|
|
||||||
struct tsc2005_spi_rd spi_y;
|
|
||||||
struct tsc2005_spi_rd spi_z1;
|
|
||||||
struct tsc2005_spi_rd spi_z2;
|
|
||||||
|
|
||||||
struct input_dev *idev;
|
struct input_dev *idev;
|
||||||
char phys[32];
|
char phys[32];
|
||||||
@ -190,62 +208,6 @@ static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value)
|
|
||||||
{
|
|
||||||
u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value;
|
|
||||||
struct spi_transfer xfer = {
|
|
||||||
.tx_buf = &tx,
|
|
||||||
.len = 4,
|
|
||||||
.bits_per_word = 24,
|
|
||||||
};
|
|
||||||
struct spi_message msg;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
spi_message_init(&msg);
|
|
||||||
spi_message_add_tail(&xfer, &msg);
|
|
||||||
|
|
||||||
error = spi_sync(ts->spi, &msg);
|
|
||||||
if (error) {
|
|
||||||
dev_err(&ts->spi->dev,
|
|
||||||
"%s: failed, register: %x, value: %x, error: %d\n",
|
|
||||||
__func__, reg, value, error);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last)
|
|
||||||
{
|
|
||||||
memset(rd, 0, sizeof(*rd));
|
|
||||||
|
|
||||||
rd->spi_tx = (reg | TSC2005_REG_READ) << 16;
|
|
||||||
rd->spi_xfer.tx_buf = &rd->spi_tx;
|
|
||||||
rd->spi_xfer.rx_buf = &rd->spi_rx;
|
|
||||||
rd->spi_xfer.len = 4;
|
|
||||||
rd->spi_xfer.bits_per_word = 24;
|
|
||||||
rd->spi_xfer.cs_change = !last;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value)
|
|
||||||
{
|
|
||||||
struct tsc2005_spi_rd spi_rd;
|
|
||||||
struct spi_message msg;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
tsc2005_setup_read(&spi_rd, reg, true);
|
|
||||||
|
|
||||||
spi_message_init(&msg);
|
|
||||||
spi_message_add_tail(&spi_rd.spi_xfer, &msg);
|
|
||||||
|
|
||||||
error = spi_sync(ts->spi, &msg);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
*value = spi_rd.spi_rx;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tsc2005_update_pen_state(struct tsc2005 *ts,
|
static void tsc2005_update_pen_state(struct tsc2005 *ts,
|
||||||
int x, int y, int pressure)
|
int x, int y, int pressure)
|
||||||
{
|
{
|
||||||
@ -274,26 +236,23 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts)
|
|||||||
struct tsc2005 *ts = _ts;
|
struct tsc2005 *ts = _ts;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int pressure;
|
unsigned int pressure;
|
||||||
u32 x, y;
|
struct tsc2005_data tsdata;
|
||||||
u32 z1, z2;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
/* read the coordinates */
|
/* read the coordinates */
|
||||||
error = spi_sync(ts->spi, &ts->spi_read_msg);
|
error = regmap_bulk_read(ts->regmap, TSC2005_REG_X, &tsdata,
|
||||||
|
TSC2005_DATA_REGS);
|
||||||
if (unlikely(error))
|
if (unlikely(error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
x = ts->spi_x.spi_rx;
|
|
||||||
y = ts->spi_y.spi_rx;
|
|
||||||
z1 = ts->spi_z1.spi_rx;
|
|
||||||
z2 = ts->spi_z2.spi_rx;
|
|
||||||
|
|
||||||
/* validate position */
|
/* validate position */
|
||||||
if (unlikely(x > MAX_12BIT || y > MAX_12BIT))
|
if (unlikely(tsdata.x > MAX_12BIT || tsdata.y > MAX_12BIT))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Skip reading if the pressure components are out of range */
|
/* Skip reading if the pressure components are out of range */
|
||||||
if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2))
|
if (unlikely(tsdata.z1 == 0 || tsdata.z2 > MAX_12BIT))
|
||||||
|
goto out;
|
||||||
|
if (unlikely(tsdata.z1 >= tsdata.z2))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -301,8 +260,8 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts)
|
|||||||
* the value before pen-up - that implies SPI fed us stale data
|
* the value before pen-up - that implies SPI fed us stale data
|
||||||
*/
|
*/
|
||||||
if (!ts->pen_down &&
|
if (!ts->pen_down &&
|
||||||
ts->in_x == x && ts->in_y == y &&
|
ts->in_x == tsdata.x && ts->in_y == tsdata.y &&
|
||||||
ts->in_z1 == z1 && ts->in_z2 == z2) {
|
ts->in_z1 == tsdata.z1 && ts->in_z2 == tsdata.z2) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,20 +269,20 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts)
|
|||||||
* At this point we are happy we have a valid and useful reading.
|
* At this point we are happy we have a valid and useful reading.
|
||||||
* Remember it for later comparisons. We may now begin downsampling.
|
* Remember it for later comparisons. We may now begin downsampling.
|
||||||
*/
|
*/
|
||||||
ts->in_x = x;
|
ts->in_x = tsdata.x;
|
||||||
ts->in_y = y;
|
ts->in_y = tsdata.y;
|
||||||
ts->in_z1 = z1;
|
ts->in_z1 = tsdata.z1;
|
||||||
ts->in_z2 = z2;
|
ts->in_z2 = tsdata.z2;
|
||||||
|
|
||||||
/* Compute touch pressure resistance using equation #1 */
|
/* Compute touch pressure resistance using equation #1 */
|
||||||
pressure = x * (z2 - z1) / z1;
|
pressure = tsdata.x * (tsdata.z2 - tsdata.z1) / tsdata.z1;
|
||||||
pressure = pressure * ts->x_plate_ohm / 4096;
|
pressure = pressure * ts->x_plate_ohm / 4096;
|
||||||
if (unlikely(pressure > MAX_12BIT))
|
if (unlikely(pressure > MAX_12BIT))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
spin_lock_irqsave(&ts->lock, flags);
|
spin_lock_irqsave(&ts->lock, flags);
|
||||||
|
|
||||||
tsc2005_update_pen_state(ts, x, y, pressure);
|
tsc2005_update_pen_state(ts, tsdata.x, tsdata.y, pressure);
|
||||||
mod_timer(&ts->penup_timer,
|
mod_timer(&ts->penup_timer,
|
||||||
jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS));
|
jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS));
|
||||||
|
|
||||||
@ -346,9 +305,9 @@ static void tsc2005_penup_timer(unsigned long data)
|
|||||||
|
|
||||||
static void tsc2005_start_scan(struct tsc2005 *ts)
|
static void tsc2005_start_scan(struct tsc2005 *ts)
|
||||||
{
|
{
|
||||||
tsc2005_write(ts, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE);
|
regmap_write(ts->regmap, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE);
|
||||||
tsc2005_write(ts, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE);
|
regmap_write(ts->regmap, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE);
|
||||||
tsc2005_write(ts, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE);
|
regmap_write(ts->regmap, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE);
|
||||||
tsc2005_cmd(ts, TSC2005_CMD_NORMAL);
|
tsc2005_cmd(ts, TSC2005_CMD_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,9 +357,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev,
|
|||||||
{
|
{
|
||||||
struct spi_device *spi = to_spi_device(dev);
|
struct spi_device *spi = to_spi_device(dev);
|
||||||
struct tsc2005 *ts = spi_get_drvdata(spi);
|
struct tsc2005 *ts = spi_get_drvdata(spi);
|
||||||
u16 temp_high;
|
unsigned int temp_high;
|
||||||
u16 temp_high_orig;
|
unsigned int temp_high_orig;
|
||||||
u16 temp_high_test;
|
unsigned int temp_high_test;
|
||||||
bool success = true;
|
bool success = true;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -411,7 +370,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev,
|
|||||||
*/
|
*/
|
||||||
__tsc2005_disable(ts);
|
__tsc2005_disable(ts);
|
||||||
|
|
||||||
error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig);
|
error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high_orig);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_warn(dev, "selftest failed: read error %d\n", error);
|
dev_warn(dev, "selftest failed: read error %d\n", error);
|
||||||
success = false;
|
success = false;
|
||||||
@ -420,14 +379,14 @@ static ssize_t tsc2005_selftest_show(struct device *dev,
|
|||||||
|
|
||||||
temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
|
temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
|
||||||
|
|
||||||
error = tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test);
|
error = regmap_write(ts->regmap, TSC2005_REG_TEMP_HIGH, temp_high_test);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_warn(dev, "selftest failed: write error %d\n", error);
|
dev_warn(dev, "selftest failed: write error %d\n", error);
|
||||||
success = false;
|
success = false;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high);
|
error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_warn(dev, "selftest failed: read error %d after write\n",
|
dev_warn(dev, "selftest failed: read error %d after write\n",
|
||||||
error);
|
error);
|
||||||
@ -450,7 +409,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* test that the reset really happened */
|
/* test that the reset really happened */
|
||||||
error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high);
|
error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_warn(dev, "selftest failed: read error %d after reset\n",
|
dev_warn(dev, "selftest failed: read error %d after reset\n",
|
||||||
error);
|
error);
|
||||||
@ -503,7 +462,7 @@ static void tsc2005_esd_work(struct work_struct *work)
|
|||||||
{
|
{
|
||||||
struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work);
|
struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work);
|
||||||
int error;
|
int error;
|
||||||
u16 r;
|
unsigned int r;
|
||||||
|
|
||||||
if (!mutex_trylock(&ts->mutex)) {
|
if (!mutex_trylock(&ts->mutex)) {
|
||||||
/*
|
/*
|
||||||
@ -519,7 +478,7 @@ static void tsc2005_esd_work(struct work_struct *work)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* We should be able to read register without disabling interrupts. */
|
/* We should be able to read register without disabling interrupts. */
|
||||||
error = tsc2005_read(ts, TSC2005_REG_CFR0, &r);
|
error = regmap_read(ts->regmap, TSC2005_REG_CFR0, &r);
|
||||||
if (!error &&
|
if (!error &&
|
||||||
!((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) {
|
!((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) {
|
||||||
goto out;
|
goto out;
|
||||||
@ -583,20 +542,6 @@ static void tsc2005_close(struct input_dev *input)
|
|||||||
mutex_unlock(&ts->mutex);
|
mutex_unlock(&ts->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tsc2005_setup_spi_xfer(struct tsc2005 *ts)
|
|
||||||
{
|
|
||||||
tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, false);
|
|
||||||
tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, false);
|
|
||||||
tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, false);
|
|
||||||
tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, true);
|
|
||||||
|
|
||||||
spi_message_init(&ts->spi_read_msg);
|
|
||||||
spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg);
|
|
||||||
spi_message_add_tail(&ts->spi_y.spi_xfer, &ts->spi_read_msg);
|
|
||||||
spi_message_add_tail(&ts->spi_z1.spi_xfer, &ts->spi_read_msg);
|
|
||||||
spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tsc2005_probe(struct spi_device *spi)
|
static int tsc2005_probe(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev);
|
const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev);
|
||||||
@ -661,6 +606,10 @@ static int tsc2005_probe(struct spi_device *spi)
|
|||||||
ts->spi = spi;
|
ts->spi = spi;
|
||||||
ts->idev = input_dev;
|
ts->idev = input_dev;
|
||||||
|
|
||||||
|
ts->regmap = devm_regmap_init_spi(spi, &tsc2005_regmap_config);
|
||||||
|
if (IS_ERR(ts->regmap))
|
||||||
|
return PTR_ERR(ts->regmap);
|
||||||
|
|
||||||
ts->x_plate_ohm = x_plate_ohm;
|
ts->x_plate_ohm = x_plate_ohm;
|
||||||
ts->esd_timeout = esd_timeout;
|
ts->esd_timeout = esd_timeout;
|
||||||
|
|
||||||
@ -700,8 +649,6 @@ static int tsc2005_probe(struct spi_device *spi)
|
|||||||
|
|
||||||
INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work);
|
INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work);
|
||||||
|
|
||||||
tsc2005_setup_spi_xfer(ts);
|
|
||||||
|
|
||||||
snprintf(ts->phys, sizeof(ts->phys),
|
snprintf(ts->phys, sizeof(ts->phys),
|
||||||
"%s/input-ts", dev_name(&spi->dev));
|
"%s/input-ts", dev_name(&spi->dev));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user