First round of fixes for IIO in the 4.0 cycle. Note a followup
set dependent on patches in the recent merge windows will follow shortly. * dht11 - fix a read off the end of an array, add some locking to prevent the read function being interrupted and make sure gpio/irq lines are not enabled for irqs during output. * iadc - timeout should be in jiffies not msecs * mpu6050 - avoid a null id from ACPI emumeration being dereferenced. * mxs-lradc - fix up some interaction issues between the touchscreen driver and iio driver. Mostly about making sure that the adc driver only affects channels that are not being used for the touchscreen. * ad2s1200 - sign extension fix for a result of c type promotion. * adis16400 - sign extension fix for a result of c type promotion. * mcp3422 - scale table was transposed. * ad5686 - use _optional regulator get to avoid a dummy reg being allocate which would cause the driver to fail to initialize. * gp2ap020a00f - select REGMAP_I2C * si7020 - revert an incorrect cleanup up and then fix the issue that made that cleanup seem like a good idea. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJU8aP7AAoJEFSFNJnE9BaIr7oQAKUtw6ScwBnCGDV+3ttEvUAl 8oSNVNKoWdBiuQK5XZHJVVVm7/n7Okt6rT8X+LjY5JsVP6lZRItAtOkwNibyyS5Q MZk3on8E7qEaASTOPPb+Izb+d2azevUaZptqTlQSaFJgs8HuBm89DwJ9H6SKZKAy kqZdjiDLx95XNAMSKiM7531Dv+TKU0BGPP8Zc0vIviUQbAcFQ6hHtfaFwU2m/hlx Cyn4UB3i2jbZmuvfL5zwHZBIjTpczlLuihQFpNAMq73pwROgbwVuQ6azBz5ib0dE gHE5AG/c/uLXO0IFvPlUmkLqQyPoTJ8dsgrjozOi+GPqWGfaBf1Iet0zfqVcJWjE jCpJqlNfcukvBnAsSMwQM/mHGVdGXd07alKjCoZsQkm0aG/DQxLn2QRWVAUno8eL zbuDCpk3rH8c5U9Ytb0likBRurM8UyTTkUhCJOpdS1iyNRe+pK8Krp/STMhc3a96 YWQxpO3p127yyc8EXdEl5N5kJwtWaV0W09vGV4oSk8A9fF7MTR2fe31pw7Si+sb3 gTsRMC1bPqF2f8UMcjxqd72IKz5GKvaIOh+J6hdN0UaITsQr+dWbPj1oAkgRQgdJ EC57hqVLJTl3S1AYtev98+LgemOARbsBYbc/FVlhTpaZPhxXOLyMsvaQ93Fa7jFr HXPJZailkvt7TgLiuoW6 =iNyv -----END PGP SIGNATURE----- Merge tag 'iio-fixes-for-4.0a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-linus Jonathan writes: First round of fixes for IIO in the 4.0 cycle. Note a followup set dependent on patches in the recent merge windows will follow shortly. * dht11 - fix a read off the end of an array, add some locking to prevent the read function being interrupted and make sure gpio/irq lines are not enabled for irqs during output. * iadc - timeout should be in jiffies not msecs * mpu6050 - avoid a null id from ACPI emumeration being dereferenced. * mxs-lradc - fix up some interaction issues between the touchscreen driver and iio driver. Mostly about making sure that the adc driver only affects channels that are not being used for the touchscreen. * ad2s1200 - sign extension fix for a result of c type promotion. * adis16400 - sign extension fix for a result of c type promotion. * mcp3422 - scale table was transposed. * ad5686 - use _optional regulator get to avoid a dummy reg being allocate which would cause the driver to fail to initialize. * gp2ap020a00f - select REGMAP_I2C * si7020 - revert an incorrect cleanup up and then fix the issue that made that cleanup seem like a good idea.
This commit is contained in:
commit
d582cb7926
@ -58,20 +58,11 @@
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
}
|
||||
|
||||
/* LSB is in nV to eliminate floating point */
|
||||
static const u32 rates_to_lsb[] = {1000000, 250000, 62500, 15625};
|
||||
|
||||
/*
|
||||
* scales calculated as:
|
||||
* rates_to_lsb[sample_rate] / (1 << pga);
|
||||
* pga is 1 for 0, 2
|
||||
*/
|
||||
|
||||
static const int mcp3422_scales[4][4] = {
|
||||
{ 1000000, 250000, 62500, 15625 },
|
||||
{ 500000 , 125000, 31250, 7812 },
|
||||
{ 250000 , 62500 , 15625, 3906 },
|
||||
{ 125000 , 31250 , 7812 , 1953 } };
|
||||
{ 1000000, 500000, 250000, 125000 },
|
||||
{ 250000 , 125000, 62500 , 31250 },
|
||||
{ 62500 , 31250 , 15625 , 7812 },
|
||||
{ 15625 , 7812 , 3906 , 1953 } };
|
||||
|
||||
/* Constant msleep times for data acquisitions */
|
||||
static const int mcp3422_read_times[4] = {
|
||||
|
@ -296,7 +296,8 @@ static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data)
|
||||
if (iadc->poll_eoc) {
|
||||
ret = iadc_poll_wait_eoc(iadc, wait);
|
||||
} else {
|
||||
ret = wait_for_completion_timeout(&iadc->complete, wait);
|
||||
ret = wait_for_completion_timeout(&iadc->complete,
|
||||
usecs_to_jiffies(wait));
|
||||
if (!ret)
|
||||
ret = -ETIMEDOUT;
|
||||
else
|
||||
|
@ -322,7 +322,7 @@ static int ad5686_probe(struct spi_device *spi)
|
||||
st = iio_priv(indio_dev);
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
st->reg = devm_regulator_get(&spi->dev, "vcc");
|
||||
st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
|
||||
if (!IS_ERR(st->reg)) {
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret)
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/wait.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
@ -39,8 +40,12 @@
|
||||
|
||||
#define DHT11_DATA_VALID_TIME 2000000000 /* 2s in ns */
|
||||
|
||||
#define DHT11_EDGES_PREAMBLE 4
|
||||
#define DHT11_EDGES_PREAMBLE 2
|
||||
#define DHT11_BITS_PER_READ 40
|
||||
/*
|
||||
* Note that when reading the sensor actually 84 edges are detected, but
|
||||
* since the last edge is not significant, we only store 83:
|
||||
*/
|
||||
#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1)
|
||||
|
||||
/* Data transmission timing (nano seconds) */
|
||||
@ -57,6 +62,7 @@ struct dht11 {
|
||||
int irq;
|
||||
|
||||
struct completion completion;
|
||||
struct mutex lock;
|
||||
|
||||
s64 timestamp;
|
||||
int temperature;
|
||||
@ -88,7 +94,7 @@ static int dht11_decode(struct dht11 *dht11, int offset)
|
||||
unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
|
||||
|
||||
/* Calculate timestamp resolution */
|
||||
for (i = 0; i < dht11->num_edges; ++i) {
|
||||
for (i = 1; i < dht11->num_edges; ++i) {
|
||||
t = dht11->edges[i].ts - dht11->edges[i-1].ts;
|
||||
if (t > 0 && t < timeres)
|
||||
timeres = t;
|
||||
@ -138,6 +144,27 @@ static int dht11_decode(struct dht11 *dht11, int offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQ handler called on GPIO edges
|
||||
*/
|
||||
static irqreturn_t dht11_handle_irq(int irq, void *data)
|
||||
{
|
||||
struct iio_dev *iio = data;
|
||||
struct dht11 *dht11 = iio_priv(iio);
|
||||
|
||||
/* TODO: Consider making the handler safe for IRQ sharing */
|
||||
if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
|
||||
dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
|
||||
dht11->edges[dht11->num_edges++].value =
|
||||
gpio_get_value(dht11->gpio);
|
||||
|
||||
if (dht11->num_edges >= DHT11_EDGES_PER_READ)
|
||||
complete(&dht11->completion);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int dht11_read_raw(struct iio_dev *iio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
int *val, int *val2, long m)
|
||||
@ -145,6 +172,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
|
||||
struct dht11 *dht11 = iio_priv(iio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dht11->lock);
|
||||
if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) {
|
||||
reinit_completion(&dht11->completion);
|
||||
|
||||
@ -157,8 +185,17 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = request_irq(dht11->irq, dht11_handle_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
iio_dev->name, iio_dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = wait_for_completion_killable_timeout(&dht11->completion,
|
||||
HZ);
|
||||
|
||||
free_irq(dht11->irq, iio_dev);
|
||||
|
||||
if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {
|
||||
dev_err(&iio_dev->dev,
|
||||
"Only %d signal edges detected\n",
|
||||
@ -185,6 +222,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
|
||||
ret = -EINVAL;
|
||||
err:
|
||||
dht11->num_edges = -1;
|
||||
mutex_unlock(&dht11->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -193,27 +231,6 @@ static const struct iio_info dht11_iio_info = {
|
||||
.read_raw = dht11_read_raw,
|
||||
};
|
||||
|
||||
/*
|
||||
* IRQ handler called on GPIO edges
|
||||
*/
|
||||
static irqreturn_t dht11_handle_irq(int irq, void *data)
|
||||
{
|
||||
struct iio_dev *iio = data;
|
||||
struct dht11 *dht11 = iio_priv(iio);
|
||||
|
||||
/* TODO: Consider making the handler safe for IRQ sharing */
|
||||
if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
|
||||
dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
|
||||
dht11->edges[dht11->num_edges++].value =
|
||||
gpio_get_value(dht11->gpio);
|
||||
|
||||
if (dht11->num_edges >= DHT11_EDGES_PER_READ)
|
||||
complete(&dht11->completion);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec dht11_chan_spec[] = {
|
||||
{ .type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), },
|
||||
@ -256,11 +273,6 @@ static int dht11_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = devm_request_irq(dev, dht11->irq, dht11_handle_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
pdev->name, iio);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1;
|
||||
dht11->num_edges = -1;
|
||||
@ -268,6 +280,7 @@ static int dht11_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, iio);
|
||||
|
||||
init_completion(&dht11->completion);
|
||||
mutex_init(&dht11->lock);
|
||||
iio->name = pdev->name;
|
||||
iio->dev.parent = &pdev->dev;
|
||||
iio->info = &dht11_iio_info;
|
||||
|
@ -45,12 +45,12 @@ static int si7020_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct i2c_client *client = iio_priv(indio_dev);
|
||||
struct i2c_client **client = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = i2c_smbus_read_word_data(client,
|
||||
ret = i2c_smbus_read_word_data(*client,
|
||||
chan->type == IIO_TEMP ?
|
||||
SI7020CMD_TEMP_HOLD :
|
||||
SI7020CMD_RH_HOLD);
|
||||
@ -126,7 +126,7 @@ static int si7020_probe(struct i2c_client *client,
|
||||
/* Wait the maximum power-up time after software reset. */
|
||||
msleep(15);
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*client));
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -414,7 +415,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
if (ret)
|
||||
return ret;
|
||||
val16 = ((val16 & 0xFFF) << 4) >> 4;
|
||||
val16 = sign_extend32(val16, 11);
|
||||
*val = val16;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
|
@ -780,7 +780,11 @@ static int inv_mpu_probe(struct i2c_client *client,
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->name = id->name;
|
||||
/* id will be NULL when enumerated via ACPI */
|
||||
if (id)
|
||||
indio_dev->name = (char *)id->name;
|
||||
else
|
||||
indio_dev->name = (char *)dev_name(&client->dev);
|
||||
indio_dev->channels = inv_mpu_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
|
||||
|
||||
|
@ -73,6 +73,7 @@ config CM36651
|
||||
config GP2AP020A00F
|
||||
tristate "Sharp GP2AP020A00F Proximity/ALS sensor"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select IRQ_WORK
|
||||
|
@ -214,11 +214,17 @@ struct mxs_lradc {
|
||||
unsigned long is_divided;
|
||||
|
||||
/*
|
||||
* Touchscreen LRADC channels receives a private slot in the CTRL4
|
||||
* register, the slot #7. Therefore only 7 slots instead of 8 in the
|
||||
* CTRL4 register can be mapped to LRADC channels when using the
|
||||
* touchscreen.
|
||||
*
|
||||
* When the touchscreen is enabled, we give it two private virtual
|
||||
* channels: #6 and #7. This means that only 6 virtual channels (instead
|
||||
* of 8) will be available for buffered capture.
|
||||
*/
|
||||
#define TOUCHSCREEN_VCHANNEL1 7
|
||||
#define TOUCHSCREEN_VCHANNEL2 6
|
||||
#define BUFFER_VCHANS_LIMITED 0x3f
|
||||
#define BUFFER_VCHANS_ALL 0xff
|
||||
u8 buffer_vchans;
|
||||
|
||||
/*
|
||||
* Furthermore, certain LRADC channels are shared between touchscreen
|
||||
* and/or touch-buttons and generic LRADC block. Therefore when using
|
||||
* either of these, these channels are not available for the regular
|
||||
@ -342,6 +348,9 @@ struct mxs_lradc {
|
||||
#define LRADC_CTRL4 0x140
|
||||
#define LRADC_CTRL4_LRADCSELECT_MASK(n) (0xf << ((n) * 4))
|
||||
#define LRADC_CTRL4_LRADCSELECT_OFFSET(n) ((n) * 4)
|
||||
#define LRADC_CTRL4_LRADCSELECT(n, x) \
|
||||
(((x) << LRADC_CTRL4_LRADCSELECT_OFFSET(n)) & \
|
||||
LRADC_CTRL4_LRADCSELECT_MASK(n))
|
||||
|
||||
#define LRADC_RESOLUTION 12
|
||||
#define LRADC_SINGLE_SAMPLE_MASK ((1 << LRADC_RESOLUTION) - 1)
|
||||
@ -416,6 +425,14 @@ static bool mxs_lradc_check_touch_event(struct mxs_lradc *lradc)
|
||||
LRADC_STATUS_TOUCH_DETECT_RAW);
|
||||
}
|
||||
|
||||
static void mxs_lradc_map_channel(struct mxs_lradc *lradc, unsigned vch,
|
||||
unsigned ch)
|
||||
{
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(vch),
|
||||
LRADC_CTRL4);
|
||||
mxs_lradc_reg_set(lradc, LRADC_CTRL4_LRADCSELECT(vch, ch), LRADC_CTRL4);
|
||||
}
|
||||
|
||||
static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
|
||||
{
|
||||
/*
|
||||
@ -450,12 +467,8 @@ static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
|
||||
LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
|
||||
LRADC_DELAY(3));
|
||||
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) |
|
||||
LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) |
|
||||
LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch), LRADC_CTRL1);
|
||||
|
||||
/* wake us again, when the complete conversion is done */
|
||||
mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch), LRADC_CTRL1);
|
||||
/*
|
||||
* after changing the touchscreen plates setting
|
||||
* the signals need some initial time to settle. Start the
|
||||
@ -509,12 +522,8 @@ static void mxs_lradc_setup_ts_pressure(struct mxs_lradc *lradc, unsigned ch1,
|
||||
LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
|
||||
LRADC_DELAY(3));
|
||||
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) |
|
||||
LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) |
|
||||
LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch2), LRADC_CTRL1);
|
||||
|
||||
/* wake us again, when the conversions are done */
|
||||
mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch2), LRADC_CTRL1);
|
||||
/*
|
||||
* after changing the touchscreen plates setting
|
||||
* the signals need some initial time to settle. Start the
|
||||
@ -580,36 +589,6 @@ static unsigned mxs_lradc_read_ts_pressure(struct mxs_lradc *lradc,
|
||||
#define TS_CH_XM 4
|
||||
#define TS_CH_YM 5
|
||||
|
||||
static int mxs_lradc_read_ts_channel(struct mxs_lradc *lradc)
|
||||
{
|
||||
u32 reg;
|
||||
int val;
|
||||
|
||||
reg = readl(lradc->base + LRADC_CTRL1);
|
||||
|
||||
/* only channels 3 to 5 are of interest here */
|
||||
if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YP)) {
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YP) |
|
||||
LRADC_CTRL1_LRADC_IRQ(TS_CH_YP), LRADC_CTRL1);
|
||||
val = mxs_lradc_read_raw_channel(lradc, TS_CH_YP);
|
||||
} else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_XM)) {
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_XM) |
|
||||
LRADC_CTRL1_LRADC_IRQ(TS_CH_XM), LRADC_CTRL1);
|
||||
val = mxs_lradc_read_raw_channel(lradc, TS_CH_XM);
|
||||
} else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YM)) {
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YM) |
|
||||
LRADC_CTRL1_LRADC_IRQ(TS_CH_YM), LRADC_CTRL1);
|
||||
val = mxs_lradc_read_raw_channel(lradc, TS_CH_YM);
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
|
||||
mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* YP(open)--+-------------+
|
||||
* | |--+
|
||||
@ -653,7 +632,8 @@ static void mxs_lradc_prepare_x_pos(struct mxs_lradc *lradc)
|
||||
mxs_lradc_reg_set(lradc, mxs_lradc_drive_x_plate(lradc), LRADC_CTRL0);
|
||||
|
||||
lradc->cur_plate = LRADC_SAMPLE_X;
|
||||
mxs_lradc_setup_ts_channel(lradc, TS_CH_YP);
|
||||
mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YP);
|
||||
mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -674,7 +654,8 @@ static void mxs_lradc_prepare_y_pos(struct mxs_lradc *lradc)
|
||||
mxs_lradc_reg_set(lradc, mxs_lradc_drive_y_plate(lradc), LRADC_CTRL0);
|
||||
|
||||
lradc->cur_plate = LRADC_SAMPLE_Y;
|
||||
mxs_lradc_setup_ts_channel(lradc, TS_CH_XM);
|
||||
mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_XM);
|
||||
mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -695,7 +676,10 @@ static void mxs_lradc_prepare_pressure(struct mxs_lradc *lradc)
|
||||
mxs_lradc_reg_set(lradc, mxs_lradc_drive_pressure(lradc), LRADC_CTRL0);
|
||||
|
||||
lradc->cur_plate = LRADC_SAMPLE_PRESSURE;
|
||||
mxs_lradc_setup_ts_pressure(lradc, TS_CH_XP, TS_CH_YM);
|
||||
mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YM);
|
||||
mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL2, TS_CH_XP);
|
||||
mxs_lradc_setup_ts_pressure(lradc, TOUCHSCREEN_VCHANNEL2,
|
||||
TOUCHSCREEN_VCHANNEL1);
|
||||
}
|
||||
|
||||
static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
|
||||
@ -708,6 +692,19 @@ static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
|
||||
mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
|
||||
}
|
||||
|
||||
static void mxs_lradc_start_touch_event(struct mxs_lradc *lradc)
|
||||
{
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
|
||||
LRADC_CTRL1);
|
||||
mxs_lradc_reg_set(lradc,
|
||||
LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1);
|
||||
/*
|
||||
* start with the Y-pos, because it uses nearly the same plate
|
||||
* settings like the touch detection
|
||||
*/
|
||||
mxs_lradc_prepare_y_pos(lradc);
|
||||
}
|
||||
|
||||
static void mxs_lradc_report_ts_event(struct mxs_lradc *lradc)
|
||||
{
|
||||
input_report_abs(lradc->ts_input, ABS_X, lradc->ts_x_pos);
|
||||
@ -725,10 +722,12 @@ static void mxs_lradc_complete_touch_event(struct mxs_lradc *lradc)
|
||||
* start a dummy conversion to burn time to settle the signals
|
||||
* note: we are not interested in the conversion's value
|
||||
*/
|
||||
mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(5));
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1);
|
||||
mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(5), LRADC_CTRL1);
|
||||
mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << 5) |
|
||||
mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(TOUCHSCREEN_VCHANNEL1));
|
||||
mxs_lradc_reg_clear(lradc,
|
||||
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
|
||||
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
|
||||
mxs_lradc_reg_wrt(lradc,
|
||||
LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) |
|
||||
LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10), /* waste 5 ms */
|
||||
LRADC_DELAY(2));
|
||||
}
|
||||
@ -760,59 +759,45 @@ static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid)
|
||||
|
||||
/* if it is released, wait for the next touch via IRQ */
|
||||
lradc->cur_plate = LRADC_TOUCH;
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1);
|
||||
mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
|
||||
mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ |
|
||||
LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
|
||||
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1);
|
||||
mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
|
||||
}
|
||||
|
||||
/* touchscreen's state machine */
|
||||
static void mxs_lradc_handle_touch(struct mxs_lradc *lradc)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (lradc->cur_plate) {
|
||||
case LRADC_TOUCH:
|
||||
/*
|
||||
* start with the Y-pos, because it uses nearly the same plate
|
||||
* settings like the touch detection
|
||||
*/
|
||||
if (mxs_lradc_check_touch_event(lradc)) {
|
||||
mxs_lradc_reg_clear(lradc,
|
||||
LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
|
||||
LRADC_CTRL1);
|
||||
mxs_lradc_prepare_y_pos(lradc);
|
||||
}
|
||||
if (mxs_lradc_check_touch_event(lradc))
|
||||
mxs_lradc_start_touch_event(lradc);
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ,
|
||||
LRADC_CTRL1);
|
||||
return;
|
||||
|
||||
case LRADC_SAMPLE_Y:
|
||||
val = mxs_lradc_read_ts_channel(lradc);
|
||||
if (val < 0) {
|
||||
mxs_lradc_enable_touch_detection(lradc); /* re-start */
|
||||
return;
|
||||
}
|
||||
lradc->ts_y_pos = val;
|
||||
lradc->ts_y_pos = mxs_lradc_read_raw_channel(lradc,
|
||||
TOUCHSCREEN_VCHANNEL1);
|
||||
mxs_lradc_prepare_x_pos(lradc);
|
||||
return;
|
||||
|
||||
case LRADC_SAMPLE_X:
|
||||
val = mxs_lradc_read_ts_channel(lradc);
|
||||
if (val < 0) {
|
||||
mxs_lradc_enable_touch_detection(lradc); /* re-start */
|
||||
return;
|
||||
}
|
||||
lradc->ts_x_pos = val;
|
||||
lradc->ts_x_pos = mxs_lradc_read_raw_channel(lradc,
|
||||
TOUCHSCREEN_VCHANNEL1);
|
||||
mxs_lradc_prepare_pressure(lradc);
|
||||
return;
|
||||
|
||||
case LRADC_SAMPLE_PRESSURE:
|
||||
lradc->ts_pressure =
|
||||
mxs_lradc_read_ts_pressure(lradc, TS_CH_XP, TS_CH_YM);
|
||||
lradc->ts_pressure = mxs_lradc_read_ts_pressure(lradc,
|
||||
TOUCHSCREEN_VCHANNEL2,
|
||||
TOUCHSCREEN_VCHANNEL1);
|
||||
mxs_lradc_complete_touch_event(lradc);
|
||||
return;
|
||||
|
||||
case LRADC_SAMPLE_VALID:
|
||||
val = mxs_lradc_read_ts_channel(lradc); /* ignore the value */
|
||||
mxs_lradc_finish_touch_event(lradc, 1);
|
||||
break;
|
||||
}
|
||||
@ -844,9 +829,9 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val)
|
||||
* used if doing raw sampling.
|
||||
*/
|
||||
if (lradc->soc == IMX28_LRADC)
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0),
|
||||
LRADC_CTRL1);
|
||||
mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
|
||||
mxs_lradc_reg_clear(lradc, 0x1, LRADC_CTRL0);
|
||||
|
||||
/* Enable / disable the divider per requirement */
|
||||
if (test_bit(chan, &lradc->is_divided))
|
||||
@ -1090,9 +1075,8 @@ static void mxs_lradc_disable_ts(struct mxs_lradc *lradc)
|
||||
{
|
||||
/* stop all interrupts from firing */
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN |
|
||||
LRADC_CTRL1_LRADC_IRQ_EN(2) | LRADC_CTRL1_LRADC_IRQ_EN(3) |
|
||||
LRADC_CTRL1_LRADC_IRQ_EN(4) | LRADC_CTRL1_LRADC_IRQ_EN(5),
|
||||
LRADC_CTRL1);
|
||||
LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
|
||||
LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
|
||||
|
||||
/* Power-down touchscreen touch-detect circuitry. */
|
||||
mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0);
|
||||
@ -1158,26 +1142,31 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data)
|
||||
struct iio_dev *iio = data;
|
||||
struct mxs_lradc *lradc = iio_priv(iio);
|
||||
unsigned long reg = readl(lradc->base + LRADC_CTRL1);
|
||||
uint32_t clr_irq = mxs_lradc_irq_mask(lradc);
|
||||
const uint32_t ts_irq_mask =
|
||||
LRADC_CTRL1_TOUCH_DETECT_IRQ |
|
||||
LRADC_CTRL1_LRADC_IRQ(2) |
|
||||
LRADC_CTRL1_LRADC_IRQ(3) |
|
||||
LRADC_CTRL1_LRADC_IRQ(4) |
|
||||
LRADC_CTRL1_LRADC_IRQ(5);
|
||||
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
|
||||
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2);
|
||||
|
||||
if (!(reg & mxs_lradc_irq_mask(lradc)))
|
||||
return IRQ_NONE;
|
||||
|
||||
if (lradc->use_touchscreen && (reg & ts_irq_mask))
|
||||
if (lradc->use_touchscreen && (reg & ts_irq_mask)) {
|
||||
mxs_lradc_handle_touch(lradc);
|
||||
|
||||
if (iio_buffer_enabled(iio))
|
||||
iio_trigger_poll(iio->trig);
|
||||
else if (reg & LRADC_CTRL1_LRADC_IRQ(0))
|
||||
complete(&lradc->completion);
|
||||
/* Make sure we don't clear the next conversion's interrupt. */
|
||||
clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
|
||||
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2));
|
||||
}
|
||||
|
||||
mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc),
|
||||
LRADC_CTRL1);
|
||||
if (iio_buffer_enabled(iio)) {
|
||||
if (reg & lradc->buffer_vchans)
|
||||
iio_trigger_poll(iio->trig);
|
||||
} else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) {
|
||||
complete(&lradc->completion);
|
||||
}
|
||||
|
||||
mxs_lradc_reg_clear(lradc, reg & clr_irq, LRADC_CTRL1);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -1289,9 +1278,10 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
|
||||
}
|
||||
|
||||
if (lradc->soc == IMX28_LRADC)
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
|
||||
LRADC_CTRL1);
|
||||
mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
|
||||
mxs_lradc_reg_clear(lradc,
|
||||
lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
|
||||
LRADC_CTRL1);
|
||||
mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0);
|
||||
|
||||
for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
|
||||
ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
|
||||
@ -1324,10 +1314,11 @@ static int mxs_lradc_buffer_postdisable(struct iio_dev *iio)
|
||||
mxs_lradc_reg_clear(lradc, LRADC_DELAY_TRIGGER_LRADCS_MASK |
|
||||
LRADC_DELAY_KICK, LRADC_DELAY(0));
|
||||
|
||||
mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0);
|
||||
mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0);
|
||||
if (lradc->soc == IMX28_LRADC)
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
|
||||
LRADC_CTRL1);
|
||||
mxs_lradc_reg_clear(lradc,
|
||||
lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
|
||||
LRADC_CTRL1);
|
||||
|
||||
kfree(lradc->buffer);
|
||||
mutex_unlock(&lradc->lock);
|
||||
@ -1353,7 +1344,7 @@ static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio,
|
||||
if (lradc->use_touchbutton)
|
||||
rsvd_chans++;
|
||||
if (lradc->use_touchscreen)
|
||||
rsvd_chans++;
|
||||
rsvd_chans += 2;
|
||||
|
||||
/* Test for attempts to map channels with special mode of operation. */
|
||||
if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS))
|
||||
@ -1413,6 +1404,13 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
|
||||
.channel = 8,
|
||||
.scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
|
||||
},
|
||||
/* Hidden channel to keep indexes */
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.indexed = 1,
|
||||
.scan_index = -1,
|
||||
.channel = 9,
|
||||
},
|
||||
MXS_ADC_CHAN(10, IIO_VOLTAGE), /* VDDIO */
|
||||
MXS_ADC_CHAN(11, IIO_VOLTAGE), /* VTH */
|
||||
MXS_ADC_CHAN(12, IIO_VOLTAGE), /* VDDA */
|
||||
@ -1583,6 +1581,11 @@ static int mxs_lradc_probe(struct platform_device *pdev)
|
||||
|
||||
touch_ret = mxs_lradc_probe_touchscreen(lradc, node);
|
||||
|
||||
if (touch_ret == 0)
|
||||
lradc->buffer_vchans = BUFFER_VCHANS_LIMITED;
|
||||
else
|
||||
lradc->buffer_vchans = BUFFER_VCHANS_ALL;
|
||||
|
||||
/* Grab all IRQ sources */
|
||||
for (i = 0; i < of_cfg->irq_count; i++) {
|
||||
lradc->irq[i] = platform_get_irq(pdev, i);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -68,7 +69,7 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev,
|
||||
break;
|
||||
case IIO_ANGL_VEL:
|
||||
vel = (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
|
||||
vel = (vel << 4) >> 4;
|
||||
vel = sign_extend32(vel, 11);
|
||||
*val = vel;
|
||||
break;
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user