diff options
-rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/adis16255/Kconfig | 10 | ||||
-rw-r--r-- | drivers/staging/adis16255/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/adis16255/TODO | 8 | ||||
-rw-r--r-- | drivers/staging/adis16255/adis16255.c | 354 |
6 files changed, 222 insertions, 155 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index e062b092073e..06d3b10d2a14 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -137,5 +137,7 @@ source "drivers/staging/cxt1e1/Kconfig" source "drivers/staging/ti-st/Kconfig" +source "drivers/staging/adis16255/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 097c158d91f7..5526870777c6 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -49,3 +49,4 @@ obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ obj-$(CONFIG_CRYSTALHD) += crystalhd/ obj-$(CONFIG_CXT1E1) += cxt1e1/ obj-$(CONFIG_TI_ST) += ti-st/ +obj-$(CONFIG_ADIS16255)) += adis16255/ diff --git a/drivers/staging/adis16255/Kconfig b/drivers/staging/adis16255/Kconfig index 3952cf95b783..a642be66adea 100644 --- a/drivers/staging/adis16255/Kconfig +++ b/drivers/staging/adis16255/Kconfig @@ -2,8 +2,10 @@ config ADIS16255 tristate "Ananlog Devices ADIS16250/16255" depends on SPI && SYSFS ---help--- - If you say yes here you get support for the Analog Devices - ADIS16250/16255 Low Power Gyroscope. + If you say yes here you get support for the Analog Devices + ADIS16250/16255 Low Power Gyroscope. The driver exposes + orientation and gyroscope value, as well as sample rate + to the sysfs. - This driver can also be built as a module. If so, the module - will be called adis16255. + This driver can also be built as a module. If so, the module + will be called adis16255. diff --git a/drivers/staging/adis16255/Makefile b/drivers/staging/adis16255/Makefile index 8057372d3781..8c3908106bfa 100644 --- a/drivers/staging/adis16255/Makefile +++ b/drivers/staging/adis16255/Makefile @@ -1 +1 @@ -obj-$(CONFIG_ADIS16255) += adis1625.o +obj-$(CONFIG_ADIS16255) += adis16255.o diff --git a/drivers/staging/adis16255/TODO b/drivers/staging/adis16255/TODO deleted file mode 100644 index 31e4ac3bdb61..000000000000 --- a/drivers/staging/adis16255/TODO +++ /dev/null @@ -1,8 +0,0 @@ -* sample rate changeable or at least readable from sysfs -* reset gyroscope -* encapsulate adis_init and adis_turn_off -* AD_CHK deletion -* chip selftest in adis_init -* reduce kernel messages to reasonable amount - -Contact: Matthias Brugger <mensch0815@gmail.com> diff --git a/drivers/staging/adis16255/adis16255.c b/drivers/staging/adis16255/adis16255.c index 8d110692a030..1ba11f00b2e7 100644 --- a/drivers/staging/adis16255/adis16255.c +++ b/drivers/staging/adis16255/adis16255.c @@ -21,6 +21,14 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* + * The driver just has a bare interface to the sysfs (sample rate in Hz, + * orientation (x, y, z) and gyroscope data in °/sec. + * + * It should be added to iio subsystem when this has left staging. + * + */ + #include <linux/init.h> #include <linux/module.h> #include <linux/device.h> @@ -62,14 +70,13 @@ * @data: Last read data from device. * @irq_adis: GPIO Number of IRQ signal * @irq: irq line manage by kernel - * @negative: indicates if sensor is upside down (negative ÿ1) + * @negative: indicates if sensor is upside down (negative == 1) * @direction: indicates axis (x, y, z) the sensor is meassuring */ struct spi_adis16255_data { struct device dev; struct spi_device *spi; s16 data; - int irq_adis; int irq; u8 negative; char direction; @@ -81,47 +88,44 @@ static int spi_adis16255_read_data(struct spi_adis16255_data *spiadis, u8 adr, u8 *rbuf) { - struct spi_device *spi ÿpiadis->spi; + struct spi_device *spi = spiadis->spi; struct spi_message msg; struct spi_transfer xfer1, xfer2; u8 *buf, *rx; int ret; - buf ÿmalloc(4, GFP_KERNEL); - if (buf ÿNULL) + buf = kzalloc(4, GFP_KERNEL); + if (buf == NULL) return -ENOMEM; - rx ÿzalloc(4, GFP_KERNEL); - if (rx ÿNULL) { - ret ÿENOMEM; + rx = kzalloc(4, GFP_KERNEL); + if (rx == NULL) { + ret = -ENOMEM; goto err_buf; } - buf[0] údr; - buf[1] ðx00; - buf[2] ðx00; - buf[3] ðx00; + buf[0] = adr; spi_message_init(&msg); memset(&xfer1, 0, sizeof(xfer1)); memset(&xfer2, 0, sizeof(xfer2)); - xfer1.tx_buf ûuf; - xfer1.rx_buf ûuf + 2; - xfer1.len ò; - xfer1.delay_usecs ù; + xfer1.tx_buf = buf; + xfer1.rx_buf = buf + 2; + xfer1.len = 2; + xfer1.delay_usecs = 9; - xfer2.tx_buf ÿx + 2; - xfer2.rx_buf ÿx; - xfer2.len ò; + xfer2.tx_buf = rx + 2; + xfer2.rx_buf = rx; + xfer2.len = 2; spi_message_add_tail(&xfer1, &msg); spi_message_add_tail(&xfer2, &msg); - ret ÿpi_sync(spi, &msg); - if (ret ÿ0) { - rbuf[0] ÿx[0]; - rbuf[1] ÿx[1]; + ret = spi_sync(spi, &msg); + if (ret == 0) { + rbuf[0] = rx[0]; + rbuf[1] = rx[1]; } kfree(rx); @@ -136,19 +140,19 @@ static int spi_adis16255_write_data(struct spi_adis16255_data *spiadis, u8 adr2, u8 *wbuf) { - struct spi_device *spi ÿpiadis->spi; + struct spi_device *spi = spiadis->spi; struct spi_message msg; struct spi_transfer xfer1, xfer2; u8 *buf, *rx; int ret; - buf ÿmalloc(4, GFP_KERNEL); - if (buf ÿNULL) + buf = kmalloc(4, GFP_KERNEL); + if (buf == NULL) return -ENOMEM; - rx ÿzalloc(4, GFP_KERNEL); - if (rx ÿNULL) { - ret ÿENOMEM; + rx = kzalloc(4, GFP_KERNEL); + if (rx == NULL) { + ret = -ENOMEM; goto err_buf; } @@ -156,27 +160,27 @@ static int spi_adis16255_write_data(struct spi_adis16255_data *spiadis, memset(&xfer1, 0, sizeof(xfer1)); memset(&xfer2, 0, sizeof(xfer2)); - buf[0] údr1 | 0x80; - buf[1] ÿwbuf; + buf[0] = adr1 | 0x80; + buf[1] = *wbuf; - buf[2] údr2 | 0x80; - buf[3] ÿ(wbuf + 1); + buf[2] = adr2 | 0x80; + buf[3] = *(wbuf + 1); - xfer1.tx_buf ûuf; - xfer1.rx_buf ÿx; - xfer1.len ò; - xfer1.delay_usecs ù; + xfer1.tx_buf = buf; + xfer1.rx_buf = rx; + xfer1.len = 2; + xfer1.delay_usecs = 9; - xfer2.tx_buf ûuf+2; - xfer2.rx_buf ÿx+2; - xfer2.len ò; + xfer2.tx_buf = buf+2; + xfer2.rx_buf = rx+2; + xfer2.len = 2; spi_message_add_tail(&xfer1, &msg); spi_message_add_tail(&xfer2, &msg); - ret ÿpi_sync(spi, &msg); - if (ret !ð) - dev_warn(&spi->dev, "wirte data to %#x %#x failed\n", + ret = spi_sync(spi, &msg); + if (ret != 0) + dev_warn(&spi->dev, "write data to %#x %#x failed\n", buf[0], buf[2]); kfree(rx); @@ -189,29 +193,31 @@ err_buf: static irqreturn_t adis_irq_thread(int irq, void *dev_id) { - struct spi_adis16255_data *spiadis ýev_id; + struct spi_adis16255_data *spiadis = dev_id; int status; - u16 value; - - status ÿspi_adis16255_read_data(spiadis, ADIS_GYRO_OUT, (u8 *)&value); - if (status ÿ0) { - /* perform on new data only... */ - if (value & 0x8000) { - /* delete error and new data bit */ - value ÿalue & 0x3fff; - /* set negative value */ - if (value & 0x2000) - value ÿalue | 0xe000; - - if (likely(spiadis->negative)) - value ÿvalue; - - spiadis->data ÿs16) value; - } - } else { + u16 value = 0; + + status = spi_adis16255_read_data(spiadis, ADIS_GYRO_OUT, (u8 *)&value); + if (status != 0) { dev_warn(&spiadis->spi->dev, "SPI FAILED\n"); + goto exit; } + /* perform on new data only... */ + if (value & 0x8000) { + /* delete error and new data bit */ + value = value & 0x3fff; + /* set negative value */ + if (value & 0x2000) + value = value | 0xe000; + + if (likely(spiadis->negative)) + value = -value; + + spiadis->data = (s16) value; + } + +exit: return IRQ_HANDLED; } @@ -221,7 +227,7 @@ ssize_t adis16255_show_data(struct device *device, struct device_attribute *da, char *buf) { - struct spi_adis16255_data *spiadis ýev_get_drvdata(device); + struct spi_adis16255_data *spiadis = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%d\n", spiadis->data); } DEVICE_ATTR(data, S_IRUGO , adis16255_show_data, NULL); @@ -230,112 +236,186 @@ ssize_t adis16255_show_direction(struct device *device, struct device_attribute *da, char *buf) { - struct spi_adis16255_data *spiadis ýev_get_drvdata(device); + struct spi_adis16255_data *spiadis = dev_get_drvdata(device); return snprintf(buf, PAGE_SIZE, "%c\n", spiadis->direction); } DEVICE_ATTR(direction, S_IRUGO , adis16255_show_direction, NULL); -static struct attribute *adis16255_attributes[] ÿ +ssize_t adis16255_show_sample_rate(struct device *device, + struct device_attribute *da, + char *buf) +{ + struct spi_adis16255_data *spiadis = dev_get_drvdata(device); + int status = 0; + u16 value = 0; + int ts = 0; + + status = spi_adis16255_read_data(spiadis, ADIS_SMPL_PRD_MSB, + (u8 *)&value); + if (status != 0) + return -EINVAL; + + if (value & 0x80) { + /* timebase = 60.54 ms */ + ts = 60540 * ((0x7f & value) + 1); + } else { + /* timebase = 1.953 ms */ + ts = 1953 * ((0x7f & value) + 1); + } + + return snprintf(buf, PAGE_SIZE, "%d\n", (1000*1000)/ts); +} +DEVICE_ATTR(sample_rate, S_IRUGO , adis16255_show_sample_rate, NULL); + +static struct attribute *adis16255_attributes[] = { &dev_attr_data.attr, &dev_attr_direction.attr, + &dev_attr_sample_rate.attr, NULL }; -static const struct attribute_group adis16255_attr_group ÿ - .attrs údis16255_attributes, +static const struct attribute_group adis16255_attr_group = { + .attrs = adis16255_attributes, }; /*-------------------------------------------------------------------------*/ -static int spi_adis16255_probe(struct spi_device *spi) +static int spi_adis16255_shutdown(struct spi_adis16255_data *spiadis) +{ + u16 value = 0; + /* turn sensor off */ + spi_adis16255_write_data(spiadis, + ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB, + (u8 *)&value); + spi_adis16255_write_data(spiadis, + ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB, + (u8 *)&value); + return 0; +} + +static int spi_adis16255_bringup(struct spi_adis16255_data *spiadis) { + int status = 0; + u16 value = 0; + + status = spi_adis16255_read_data(spiadis, ADIS_GYRO_SCALE, + (u8 *)&value); + if (status != 0) + goto err; + if (value != 0x0800) { + dev_warn(&spiadis->spi->dev, "Scale factor is none default" + "value (%.4x)\n", value); + } + + /* timebase = 1.953 ms, Ns = 0 -> 512 Hz sample rate */ + value = 0x0001; + status = spi_adis16255_write_data(spiadis, + ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB, + (u8 *)&value); + if (status != 0) + goto err; + + /* start internal self-test */ + value = 0x0400; + status = spi_adis16255_write_data(spiadis, + ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB, + (u8 *)&value); + if (status != 0) + goto err; + + /* wait 35 ms to finish self-test */ + msleep(35); + + value = 0x0000; + status = spi_adis16255_read_data(spiadis, ADIS_STATUS, + (u8 *)&value); + if (status != 0) + goto err; + + if (value & 0x23) { + if (value & 0x20) { + dev_warn(&spiadis->spi->dev, "self-test error\n"); + status = -ENODEV; + goto err; + } else if (value & 0x3) { + dev_warn(&spiadis->spi->dev, "Sensor voltage" + "out of range.\n"); + status = -ENODEV; + goto err; + } + } -#define AD_CHK(_ss)\ - do {\ - status ÿss;\ - if (status !ð)\ - goto irq_err;\ - } while (0); + /* set interrupt to active high on DIO0 when data ready */ + value = 0x0006; + status = spi_adis16255_write_data(spiadis, + ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB, + (u8 *)&value); + if (status != 0) + goto err; + return status; + +err: + spi_adis16255_shutdown(spiadis); + return status; +} + +/*-------------------------------------------------------------------------*/ - struct adis16255_init_data *init_data ÿpi->dev.platform_data; +static int spi_adis16255_probe(struct spi_device *spi) +{ + + struct adis16255_init_data *init_data = spi->dev.platform_data; struct spi_adis16255_data *spiadis; - int status ð; - u16 value; + int status = 0; - spiadis ÿzalloc(sizeof(*spiadis), GFP_KERNEL); + spiadis = kzalloc(sizeof(*spiadis), GFP_KERNEL); if (!spiadis) return -ENOMEM; - spiadis->spi ÿpi; - spiadis->irq_adis ÿnit_data->irq; - spiadis->direction ÿnit_data->direction; + spiadis->spi = spi; + spiadis->direction = init_data->direction; if (init_data->negative) - spiadis->negative ñ; + spiadis->negative = 1; - status ÿpio_request(spiadis->irq_adis, "adis16255"); - if (status !ð) + status = gpio_request(init_data->irq, "adis16255"); + if (status != 0) goto err; - status ÿpio_direction_input(spiadis->irq_adis); - if (status !ð) + status = gpio_direction_input(init_data->irq); + if (status != 0) goto gpio_err; - spiadis->irq ÿpio_to_irq(spiadis->irq_adis); + spiadis->irq = gpio_to_irq(init_data->irq); - status ÿequest_threaded_irq(spiadis->irq, + status = request_threaded_irq(spiadis->irq, NULL, adis_irq_thread, IRQF_DISABLED, "adis-driver", spiadis); - if (status !ð) { + if (status != 0) { dev_err(&spi->dev, "IRQ request failed\n"); goto gpio_err; } - dev_dbg(&spi->dev, "GPIO %d IRQ %d\n", spiadis->irq_adis, spiadis->irq); + dev_dbg(&spi->dev, "GPIO %d IRQ %d\n", init_data->irq, spiadis->irq); dev_set_drvdata(&spi->dev, spiadis); - AD_CHK(sysfs_create_group(&spi->dev.kobj, &adis16255_attr_group)); - - dev_info(&spi->dev, "spi_adis16255 driver added!\n"); + status = sysfs_create_group(&spi->dev.kobj, &adis16255_attr_group); + if (status != 0) + goto irq_err; - AD_CHK(spi_adis16255_read_data(spiadis, ADIS_SUPPLY_OUT, (u8 *)&value)); - dev_info(&spi->dev, "sensor works with %d mV (%.4x)!\n", - ((value & 0x0fff)*18315)/10000, - (value & 0x0fff)); + status = spi_adis16255_bringup(spiadis); + if (status != 0) + goto irq_err; - AD_CHK(spi_adis16255_read_data(spiadis, ADIS_GYRO_SCALE, (u8 *)&value)); - dev_info(&spi->dev, "adis GYRO_SCALE is %.4x\n", value); - - AD_CHK(spi_adis16255_read_data(spiadis, ADIS_STATUS, (u8 *)&value)); - dev_info(&spi->dev, "adis STATUS is %.4x\n", value); - - /* timebase ñ.953 ms, Ns ð -> 512 Hz sample rate */ - value ÿ0x0001; - AD_CHK(spi_adis16255_write_data(spiadis, - ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB, - (u8 *)&value)); - value ðx0000; - AD_CHK(spi_adis16255_read_data(spiadis, ADIS_SMPL_PRD_MSB, - (u8 *)&value)); - dev_info(&spi->dev, "adis SMP_PRD is %.4x\n", value); - - /* set interrupt on new data... */ - value ðx0006; - AD_CHK(spi_adis16255_write_data(spiadis, - ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB, - (u8 *)&value)); - value ðx0000; - AD_CHK(spi_adis16255_read_data(spiadis, ADIS_MSC_CTRL_MSB, - (u8 *)&value)); - dev_info(&spi->dev, "adis MSC_CONTROL is %.4x\n", value); + dev_info(&spi->dev, "spi_adis16255 driver added!\n"); return status; irq_err: free_irq(spiadis->irq, spiadis); gpio_err: - gpio_free(spiadis->irq_adis); + gpio_free(init_data->irq); err: kfree(spiadis); return status; @@ -343,22 +423,12 @@ err: static int spi_adis16255_remove(struct spi_device *spi) { - u16 value ð; - struct spi_adis16255_data *spiadis ýev_get_drvdata(&spi->dev); - - /* turn sensor off */ - spi_adis16255_write_data(spiadis, - ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB, - (u8 *)&value); - spi_adis16255_write_data(spiadis, - ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB, - (u8 *)&value); + struct spi_adis16255_data *spiadis = dev_get_drvdata(&spi->dev); - dev_info(&spi->dev, "unregister: GPIO %d IRQ %d\n", - spiadis->irq_adis, spiadis->irq); + spi_adis16255_shutdown(spiadis); free_irq(spiadis->irq, spiadis); - gpio_free(spiadis->irq_adis); + gpio_free(irq_to_gpio(spiadis->irq)); sysfs_remove_group(&spiadis->spi->dev.kobj, &adis16255_attr_group); @@ -368,13 +438,13 @@ static int spi_adis16255_remove(struct spi_device *spi) return 0; } -static struct spi_driver spi_adis16255_drv ÿ - .driver ÿ - .name ÿ"spi_adis16255", - .owner ÿHIS_MODULE, +static struct spi_driver spi_adis16255_drv = { + .driver = { + .name = "spi_adis16255", + .owner = THIS_MODULE, }, - .probe ÿpi_adis16255_probe, - .remove ÿ __devexit_p(spi_adis16255_remove), + .probe = spi_adis16255_probe, + .remove = __devexit_p(spi_adis16255_remove), }; /*-------------------------------------------------------------------------*/ |