Input: ads7846 - fix cache line sharing issue
We had a report a while back that the ads7846 driver had some issues when used with DMA-based SPI controllers (like atmel_spi) on systems where main memory is not DMA-coherent (most non-x86 boards). Allocate memory potentially used for DMA separately to avoid cache line issues. Reported-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
@@ -69,6 +69,17 @@ struct ts_event {
|
|||||||
int ignore;
|
int ignore;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We allocate this separately to avoid cache line sharing issues when
|
||||||
|
* driver is used with DMA-based SPI controllers (like atmel_spi) on
|
||||||
|
* systems where main memory is not DMA-coherent (most non-x86 boards).
|
||||||
|
*/
|
||||||
|
struct ads7846_packet {
|
||||||
|
u8 read_x, read_y, read_z1, read_z2, pwrdown;
|
||||||
|
u16 dummy; /* for the pwrdown read */
|
||||||
|
struct ts_event tc;
|
||||||
|
};
|
||||||
|
|
||||||
struct ads7846 {
|
struct ads7846 {
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
char phys[32];
|
char phys[32];
|
||||||
@@ -86,9 +97,7 @@ struct ads7846 {
|
|||||||
u16 x_plate_ohms;
|
u16 x_plate_ohms;
|
||||||
u16 pressure_max;
|
u16 pressure_max;
|
||||||
|
|
||||||
u8 read_x, read_y, read_z1, read_z2, pwrdown;
|
struct ads7846_packet *packet;
|
||||||
u16 dummy; /* for the pwrdown read */
|
|
||||||
struct ts_event tc;
|
|
||||||
|
|
||||||
struct spi_transfer xfer[18];
|
struct spi_transfer xfer[18];
|
||||||
struct spi_message msg[5];
|
struct spi_message msg[5];
|
||||||
@@ -513,16 +522,17 @@ static int get_pendown_state(struct ads7846 *ts)
|
|||||||
static void ads7846_rx(void *ads)
|
static void ads7846_rx(void *ads)
|
||||||
{
|
{
|
||||||
struct ads7846 *ts = ads;
|
struct ads7846 *ts = ads;
|
||||||
|
struct ads7846_packet *packet = ts->packet;
|
||||||
unsigned Rt;
|
unsigned Rt;
|
||||||
u16 x, y, z1, z2;
|
u16 x, y, z1, z2;
|
||||||
|
|
||||||
/* ads7846_rx_val() did in-place conversion (including byteswap) from
|
/* ads7846_rx_val() did in-place conversion (including byteswap) from
|
||||||
* on-the-wire format as part of debouncing to get stable readings.
|
* on-the-wire format as part of debouncing to get stable readings.
|
||||||
*/
|
*/
|
||||||
x = ts->tc.x;
|
x = packet->tc.x;
|
||||||
y = ts->tc.y;
|
y = packet->tc.y;
|
||||||
z1 = ts->tc.z1;
|
z1 = packet->tc.z1;
|
||||||
z2 = ts->tc.z2;
|
z2 = packet->tc.z2;
|
||||||
|
|
||||||
/* range filtering */
|
/* range filtering */
|
||||||
if (x == MAX_12BIT)
|
if (x == MAX_12BIT)
|
||||||
@@ -546,10 +556,10 @@ static void ads7846_rx(void *ads)
|
|||||||
* the maximum. Don't report it to user space, repeat at least
|
* the maximum. Don't report it to user space, repeat at least
|
||||||
* once more the measurement
|
* once more the measurement
|
||||||
*/
|
*/
|
||||||
if (ts->tc.ignore || Rt > ts->pressure_max) {
|
if (packet->tc.ignore || Rt > ts->pressure_max) {
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
pr_debug("%s: ignored %d pressure %d\n",
|
pr_debug("%s: ignored %d pressure %d\n",
|
||||||
ts->spi->dev.bus_id, ts->tc.ignore, Rt);
|
ts->spi->dev.bus_id, packet->tc.ignore, Rt);
|
||||||
#endif
|
#endif
|
||||||
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
|
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
|
||||||
HRTIMER_MODE_REL);
|
HRTIMER_MODE_REL);
|
||||||
@@ -642,6 +652,7 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val)
|
|||||||
static void ads7846_rx_val(void *ads)
|
static void ads7846_rx_val(void *ads)
|
||||||
{
|
{
|
||||||
struct ads7846 *ts = ads;
|
struct ads7846 *ts = ads;
|
||||||
|
struct ads7846_packet *packet = ts->packet;
|
||||||
struct spi_message *m;
|
struct spi_message *m;
|
||||||
struct spi_transfer *t;
|
struct spi_transfer *t;
|
||||||
int val;
|
int val;
|
||||||
@@ -661,7 +672,7 @@ static void ads7846_rx_val(void *ads)
|
|||||||
case ADS7846_FILTER_REPEAT:
|
case ADS7846_FILTER_REPEAT:
|
||||||
break;
|
break;
|
||||||
case ADS7846_FILTER_IGNORE:
|
case ADS7846_FILTER_IGNORE:
|
||||||
ts->tc.ignore = 1;
|
packet->tc.ignore = 1;
|
||||||
/* Last message will contain ads7846_rx() as the
|
/* Last message will contain ads7846_rx() as the
|
||||||
* completion function.
|
* completion function.
|
||||||
*/
|
*/
|
||||||
@@ -669,7 +680,7 @@ static void ads7846_rx_val(void *ads)
|
|||||||
break;
|
break;
|
||||||
case ADS7846_FILTER_OK:
|
case ADS7846_FILTER_OK:
|
||||||
*(u16 *)t->rx_buf = val;
|
*(u16 *)t->rx_buf = val;
|
||||||
ts->tc.ignore = 0;
|
packet->tc.ignore = 0;
|
||||||
m = &ts->msg[++ts->msg_idx];
|
m = &ts->msg[++ts->msg_idx];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -774,7 +785,6 @@ static void ads7846_disable(struct ads7846 *ts)
|
|||||||
/* we know the chip's in lowpower mode since we always
|
/* we know the chip's in lowpower mode since we always
|
||||||
* leave it that way after every request
|
* leave it that way after every request
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must be called with ts->lock held */
|
/* Must be called with ts->lock held */
|
||||||
@@ -850,6 +860,7 @@ static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
|
|||||||
static int __devinit ads7846_probe(struct spi_device *spi)
|
static int __devinit ads7846_probe(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct ads7846 *ts;
|
struct ads7846 *ts;
|
||||||
|
struct ads7846_packet *packet;
|
||||||
struct input_dev *input_dev;
|
struct input_dev *input_dev;
|
||||||
struct ads7846_platform_data *pdata = spi->dev.platform_data;
|
struct ads7846_platform_data *pdata = spi->dev.platform_data;
|
||||||
struct spi_message *m;
|
struct spi_message *m;
|
||||||
@@ -885,14 +896,16 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
|
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
|
||||||
|
packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
|
||||||
input_dev = input_allocate_device();
|
input_dev = input_allocate_device();
|
||||||
if (!ts || !input_dev) {
|
if (!ts || !packet || !input_dev) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto err_free_mem;
|
goto err_free_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_set_drvdata(&spi->dev, ts);
|
dev_set_drvdata(&spi->dev, ts);
|
||||||
|
|
||||||
|
ts->packet = packet;
|
||||||
ts->spi = spi;
|
ts->spi = spi;
|
||||||
ts->input = input_dev;
|
ts->input = input_dev;
|
||||||
ts->vref_mv = pdata->vref_mv;
|
ts->vref_mv = pdata->vref_mv;
|
||||||
@@ -964,13 +977,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
spi_message_init(m);
|
spi_message_init(m);
|
||||||
|
|
||||||
/* y- still on; turn on only y+ (and ADC) */
|
/* y- still on; turn on only y+ (and ADC) */
|
||||||
ts->read_y = READ_Y(vref);
|
packet->read_y = READ_Y(vref);
|
||||||
x->tx_buf = &ts->read_y;
|
x->tx_buf = &packet->read_y;
|
||||||
x->len = 1;
|
x->len = 1;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->rx_buf = &ts->tc.y;
|
x->rx_buf = &packet->tc.y;
|
||||||
x->len = 2;
|
x->len = 2;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
@@ -982,12 +995,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
x->delay_usecs = pdata->settle_delay_usecs;
|
x->delay_usecs = pdata->settle_delay_usecs;
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->tx_buf = &ts->read_y;
|
x->tx_buf = &packet->read_y;
|
||||||
x->len = 1;
|
x->len = 1;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->rx_buf = &ts->tc.y;
|
x->rx_buf = &packet->tc.y;
|
||||||
x->len = 2;
|
x->len = 2;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
}
|
}
|
||||||
@@ -1000,13 +1013,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
|
|
||||||
/* turn y- off, x+ on, then leave in lowpower */
|
/* turn y- off, x+ on, then leave in lowpower */
|
||||||
x++;
|
x++;
|
||||||
ts->read_x = READ_X(vref);
|
packet->read_x = READ_X(vref);
|
||||||
x->tx_buf = &ts->read_x;
|
x->tx_buf = &packet->read_x;
|
||||||
x->len = 1;
|
x->len = 1;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->rx_buf = &ts->tc.x;
|
x->rx_buf = &packet->tc.x;
|
||||||
x->len = 2;
|
x->len = 2;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
@@ -1015,12 +1028,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
x->delay_usecs = pdata->settle_delay_usecs;
|
x->delay_usecs = pdata->settle_delay_usecs;
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->tx_buf = &ts->read_x;
|
x->tx_buf = &packet->read_x;
|
||||||
x->len = 1;
|
x->len = 1;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->rx_buf = &ts->tc.x;
|
x->rx_buf = &packet->tc.x;
|
||||||
x->len = 2;
|
x->len = 2;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
}
|
}
|
||||||
@@ -1034,13 +1047,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
spi_message_init(m);
|
spi_message_init(m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
ts->read_z1 = READ_Z1(vref);
|
packet->read_z1 = READ_Z1(vref);
|
||||||
x->tx_buf = &ts->read_z1;
|
x->tx_buf = &packet->read_z1;
|
||||||
x->len = 1;
|
x->len = 1;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->rx_buf = &ts->tc.z1;
|
x->rx_buf = &packet->tc.z1;
|
||||||
x->len = 2;
|
x->len = 2;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
@@ -1049,12 +1062,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
x->delay_usecs = pdata->settle_delay_usecs;
|
x->delay_usecs = pdata->settle_delay_usecs;
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->tx_buf = &ts->read_z1;
|
x->tx_buf = &packet->read_z1;
|
||||||
x->len = 1;
|
x->len = 1;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->rx_buf = &ts->tc.z1;
|
x->rx_buf = &packet->tc.z1;
|
||||||
x->len = 2;
|
x->len = 2;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
}
|
}
|
||||||
@@ -1066,13 +1079,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
spi_message_init(m);
|
spi_message_init(m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
ts->read_z2 = READ_Z2(vref);
|
packet->read_z2 = READ_Z2(vref);
|
||||||
x->tx_buf = &ts->read_z2;
|
x->tx_buf = &packet->read_z2;
|
||||||
x->len = 1;
|
x->len = 1;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->rx_buf = &ts->tc.z2;
|
x->rx_buf = &packet->tc.z2;
|
||||||
x->len = 2;
|
x->len = 2;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
@@ -1081,12 +1094,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
x->delay_usecs = pdata->settle_delay_usecs;
|
x->delay_usecs = pdata->settle_delay_usecs;
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->tx_buf = &ts->read_z2;
|
x->tx_buf = &packet->read_z2;
|
||||||
x->len = 1;
|
x->len = 1;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->rx_buf = &ts->tc.z2;
|
x->rx_buf = &packet->tc.z2;
|
||||||
x->len = 2;
|
x->len = 2;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
}
|
}
|
||||||
@@ -1100,13 +1113,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
spi_message_init(m);
|
spi_message_init(m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
ts->pwrdown = PWRDOWN;
|
packet->pwrdown = PWRDOWN;
|
||||||
x->tx_buf = &ts->pwrdown;
|
x->tx_buf = &packet->pwrdown;
|
||||||
x->len = 1;
|
x->len = 1;
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->rx_buf = &ts->dummy;
|
x->rx_buf = &packet->dummy;
|
||||||
x->len = 2;
|
x->len = 2;
|
||||||
CS_CHANGE(*x);
|
CS_CHANGE(*x);
|
||||||
spi_message_add_tail(x, m);
|
spi_message_add_tail(x, m);
|
||||||
@@ -1159,6 +1172,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
ts->filter_cleanup(ts->filter_data);
|
ts->filter_cleanup(ts->filter_data);
|
||||||
err_free_mem:
|
err_free_mem:
|
||||||
input_free_device(input_dev);
|
input_free_device(input_dev);
|
||||||
|
kfree(packet);
|
||||||
kfree(ts);
|
kfree(ts);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -1184,6 +1198,7 @@ static int __devexit ads7846_remove(struct spi_device *spi)
|
|||||||
if (ts->filter_cleanup)
|
if (ts->filter_cleanup)
|
||||||
ts->filter_cleanup(ts->filter_data);
|
ts->filter_cleanup(ts->filter_data);
|
||||||
|
|
||||||
|
kfree(ts->packet);
|
||||||
kfree(ts);
|
kfree(ts);
|
||||||
|
|
||||||
dev_dbg(&spi->dev, "unregistered touchscreen\n");
|
dev_dbg(&spi->dev, "unregistered touchscreen\n");
|
||||||
|
Reference in New Issue
Block a user