mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
staging driver fixes for 4.0-rc3
Here are some IIO and staging driver fixes for 4.0-rc3. Details are in the shortlog, nothing major, mostly IIO fixes for reported issues. All have been in linux-next successfully. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlT8RKEACgkQMUfUDdst+ylRTACeJHh8MIafzeNX1mn+YJKSvVVa ks0AoIcvKsvIeEiWvJsNepHaHlfMs4R6 =Ppc/ -----END PGP SIGNATURE----- Merge tag 'staging-4.0-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging Pull staging driver fixes from Greg KH: "Here are some IIO and staging driver fixes for 4.0-rc3. Details are in the shortlog, nothing major, mostly IIO fixes for reported issues. All have been in linux-next successfully" * tag 'staging-4.0-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (23 commits) staging: comedi: adv_pci1710: fix AI INSN_READ for non-zero channel staging: comedi: vmk80xx: remove "firmware version" kernel messages staging: comedi: comedi_isadma: fix "stalled" detect in comedi_isadma_disable_on_sample() iio: ak8975: fix AK09911 dependencies iio: common: ssp_sensors: Protect PM-only functions to kill warning IIO: si7020: Allocate correct amount of memory in devm_iio_device_alloc Revert "iio:humidity:si7020: fix pointer to i2c client" iio: light: gp2ap020a00f: Select REGMAP_I2C iio: light: jsa1212: Select REGMAP_I2C iio: ad5686: fix optional reference voltage declaration iio:adc:mcp3422 Fix incorrect scales table iio: mxs-lradc: fix iio channel map regression iio: imu: adis16400: Fix sign extension staging: iio: ad2s1200: Fix sign extension iio: mxs-lradc: only update the buffer when its conversions have finished iio: mxs-lradc: make ADC reads not unschedule touchscreen conversions iio: mxs-lradc: make ADC reads not disable touchscreen interrupts iio: mxs-lradc: separate touchscreen and buffer virtual channels iio: imu: inv_mpu6050: Prevent dereferencing NULL iio: iadc: wait_for_completion_timeout time in jiffies ...
This commit is contained in:
commit
47df986b68
15 changed files with 176 additions and 227 deletions
|
@ -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
|
||||
|
|
|
@ -640,6 +640,7 @@ static int ssp_remove(struct spi_device *spi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int ssp_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
@ -688,6 +689,7 @@ static int ssp_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static const struct dev_pm_ops ssp_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume)
|
||||
|
|
|
@ -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
|
||||
|
@ -126,6 +127,7 @@ config HID_SENSOR_PROX
|
|||
config JSA1212
|
||||
tristate "JSA1212 ALS and proximity sensor driver"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here if you want to build a IIO driver for JSA1212
|
||||
proximity & ALS sensor device.
|
||||
|
|
|
@ -18,6 +18,8 @@ config AK8975
|
|||
|
||||
config AK09911
|
||||
tristate "Asahi Kasei AK09911 3-axis Compass"
|
||||
depends on I2C
|
||||
depends on GPIOLIB
|
||||
select AK8975
|
||||
help
|
||||
Deprecated: AK09911 is now supported by AK8975 driver.
|
||||
|
|
|
@ -426,7 +426,6 @@ static int pci171x_ai_insn_read(struct comedi_device *dev,
|
|||
unsigned int *data)
|
||||
{
|
||||
struct pci1710_private *devpriv = dev->private;
|
||||
unsigned int chan = CR_CHAN(insn->chanspec);
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
|
@ -447,7 +446,7 @@ static int pci171x_ai_insn_read(struct comedi_device *dev,
|
|||
if (ret)
|
||||
break;
|
||||
|
||||
ret = pci171x_ai_read_sample(dev, s, chan, &val);
|
||||
ret = pci171x_ai_read_sample(dev, s, 0, &val);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
|
|
|
@ -91,9 +91,10 @@ unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan,
|
|||
stalled++;
|
||||
if (stalled > 10)
|
||||
break;
|
||||
} else {
|
||||
residue = new_residue;
|
||||
stalled = 0;
|
||||
}
|
||||
residue = new_residue;
|
||||
stalled = 0;
|
||||
}
|
||||
return residue;
|
||||
}
|
||||
|
|
|
@ -103,11 +103,6 @@ enum vmk80xx_model {
|
|||
VMK8061_MODEL
|
||||
};
|
||||
|
||||
struct firmware_version {
|
||||
unsigned char ic3_vers[32]; /* USB-Controller */
|
||||
unsigned char ic6_vers[32]; /* CPU */
|
||||
};
|
||||
|
||||
static const struct comedi_lrange vmk8061_range = {
|
||||
2, {
|
||||
UNI_RANGE(5),
|
||||
|
@ -156,68 +151,12 @@ static const struct vmk80xx_board vmk80xx_boardinfo[] = {
|
|||
struct vmk80xx_private {
|
||||
struct usb_endpoint_descriptor *ep_rx;
|
||||
struct usb_endpoint_descriptor *ep_tx;
|
||||
struct firmware_version fw;
|
||||
struct semaphore limit_sem;
|
||||
unsigned char *usb_rx_buf;
|
||||
unsigned char *usb_tx_buf;
|
||||
enum vmk80xx_model model;
|
||||
};
|
||||
|
||||
static int vmk80xx_check_data_link(struct comedi_device *dev)
|
||||
{
|
||||
struct vmk80xx_private *devpriv = dev->private;
|
||||
struct usb_device *usb = comedi_to_usb_dev(dev);
|
||||
unsigned int tx_pipe;
|
||||
unsigned int rx_pipe;
|
||||
unsigned char tx[1];
|
||||
unsigned char rx[2];
|
||||
|
||||
tx_pipe = usb_sndbulkpipe(usb, 0x01);
|
||||
rx_pipe = usb_rcvbulkpipe(usb, 0x81);
|
||||
|
||||
tx[0] = VMK8061_CMD_RD_PWR_STAT;
|
||||
|
||||
/*
|
||||
* Check that IC6 (PIC16F871) is powered and
|
||||
* running and the data link between IC3 and
|
||||
* IC6 is working properly
|
||||
*/
|
||||
usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
|
||||
usb_bulk_msg(usb, rx_pipe, rx, 2, NULL, HZ * 10);
|
||||
|
||||
return (int)rx[1];
|
||||
}
|
||||
|
||||
static void vmk80xx_read_eeprom(struct comedi_device *dev, int flag)
|
||||
{
|
||||
struct vmk80xx_private *devpriv = dev->private;
|
||||
struct usb_device *usb = comedi_to_usb_dev(dev);
|
||||
unsigned int tx_pipe;
|
||||
unsigned int rx_pipe;
|
||||
unsigned char tx[1];
|
||||
unsigned char rx[64];
|
||||
int cnt;
|
||||
|
||||
tx_pipe = usb_sndbulkpipe(usb, 0x01);
|
||||
rx_pipe = usb_rcvbulkpipe(usb, 0x81);
|
||||
|
||||
tx[0] = VMK8061_CMD_RD_VERSION;
|
||||
|
||||
/*
|
||||
* Read the firmware version info of IC3 and
|
||||
* IC6 from the internal EEPROM of the IC
|
||||
*/
|
||||
usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval);
|
||||
usb_bulk_msg(usb, rx_pipe, rx, 64, &cnt, HZ * 10);
|
||||
|
||||
rx[cnt] = '\0';
|
||||
|
||||
if (flag & IC3_VERSION)
|
||||
strncpy(devpriv->fw.ic3_vers, rx + 1, 24);
|
||||
else /* IC6_VERSION */
|
||||
strncpy(devpriv->fw.ic6_vers, rx + 25, 24);
|
||||
}
|
||||
|
||||
static void vmk80xx_do_bulk_msg(struct comedi_device *dev)
|
||||
{
|
||||
struct vmk80xx_private *devpriv = dev->private;
|
||||
|
@ -878,16 +817,6 @@ static int vmk80xx_auto_attach(struct comedi_device *dev,
|
|||
|
||||
usb_set_intfdata(intf, devpriv);
|
||||
|
||||
if (devpriv->model == VMK8061_MODEL) {
|
||||
vmk80xx_read_eeprom(dev, IC3_VERSION);
|
||||
dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers);
|
||||
|
||||
if (vmk80xx_check_data_link(dev)) {
|
||||
vmk80xx_read_eeprom(dev, IC6_VERSION);
|
||||
dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers);
|
||||
}
|
||||
}
|
||||
|
||||
if (devpriv->model == VMK8055_MODEL)
|
||||
vmk80xx_reset_device(dev);
|
||||
|
||||
|
|
|
@ -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 a new issue