This patch solves some issues mentioned in TODO list: - sample rate exported to sysfs - spi_adis16255_bringup and spi_adis16255_shutdown encapsulated - chip selftest in spi_adis16255_bringup - kernel messages reduced to a reasonable number Signed-off-by: Matthias Brugger <mensch0815@xxxxxxxxx> --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/adis16255/Kconfig | 10 +- drivers/staging/adis16255/Makefile | 2 +- drivers/staging/adis16255/TODO | 5 - drivers/staging/adis16255/adis16255.c | 206 +++++++++++++++++++++------------ 6 files changed, 144 insertions(+), 82 deletions(-) diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 7696a66..2670b6c 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -139,5 +139,7 @@ source "drivers/staging/dt3155/Kconfig" source "drivers/staging/crystalhd/Kconfig" +source "drivers/staging/adis16255/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index ea2e70e..fd49d83 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -51,3 +51,4 @@ obj-$(CONFIG_PCMCIA_NETWAVE) += netwave/ obj-$(CONFIG_FB_SM7XX) += sm7xx/ obj-$(CONFIG_DT3155) += dt3155/ obj-$(CONFIG_CRYSTALHD) += crystalhd/ +obj-$(CONFIG_ADIS16255) += adis16255/ diff --git a/drivers/staging/adis16255/Kconfig b/drivers/staging/adis16255/Kconfig index 3952cf9..a642be6 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 796dac4..8c39081 100644 --- a/drivers/staging/adis16255/Makefile +++ b/drivers/staging/adis16255/Makefile @@ -1 +1 @@ -obj-$(CONFIG_ADIS16255) += adis16255.o +obj-$(CONFIG_ADIS16255) += adis16255.o diff --git a/drivers/staging/adis16255/TODO b/drivers/staging/adis16255/TODO index 31e4ac3..ec60f31 100644 --- a/drivers/staging/adis16255/TODO +++ b/drivers/staging/adis16255/TODO @@ -1,8 +1,3 @@ -* 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@xxxxxxxxx> diff --git a/drivers/staging/adis16255/adis16255.c b/drivers/staging/adis16255/adis16255.c index 9a8ced1..1ba11f0 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> @@ -69,7 +77,6 @@ struct spi_adis16255_data { struct device dev; struct spi_device *spi; s16 data; - int irq_adis; int irq; u8 negative; char direction; @@ -87,7 +94,7 @@ static int spi_adis16255_read_data(struct spi_adis16255_data *spiadis, u8 *buf, *rx; int ret; - buf = kmalloc(4, GFP_KERNEL); + buf = kzalloc(4, GFP_KERNEL); if (buf == NULL) return -ENOMEM; @@ -98,9 +105,6 @@ static int spi_adis16255_read_data(struct spi_adis16255_data *spiadis, } buf[0] = adr; - buf[1] = 0x00; - buf[2] = 0x00; - buf[3] = 0x00; spi_message_init(&msg); memset(&xfer1, 0, sizeof(xfer1)); @@ -176,7 +180,7 @@ static int spi_adis16255_write_data(struct spi_adis16255_data *spiadis, ret = spi_sync(spi, &msg); if (ret != 0) - dev_warn(&spi->dev, "wirte data to %#x %#x failed\n", + dev_warn(&spi->dev, "write data to %#x %#x failed\n", buf[0], buf[2]); kfree(rx); @@ -191,27 +195,29 @@ static irqreturn_t adis_irq_thread(int irq, void *dev_id) { struct spi_adis16255_data *spiadis = dev_id; int status; - u16 value; + u16 value = 0; 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 = value & 0x3fff; - /* set negative value */ - if (value & 0x2000) - value = value | 0xe000; - - if (likely(spiadis->negative)) - value = -value; - - spiadis->data = (s16) value; - } - } else { + 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; } @@ -235,9 +241,36 @@ ssize_t adis16255_show_direction(struct device *device, } DEVICE_ATTR(direction, S_IRUGO , adis16255_show_direction, NULL); +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 }; @@ -260,43 +293,100 @@ static int spi_adis16255_shutdown(struct spi_adis16255_data *spiadis) 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; + } + } + + /* 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; +} + /*-------------------------------------------------------------------------*/ static int spi_adis16255_probe(struct spi_device *spi) { -#define AD_CHK(_ss)\ - do {\ - status = _ss;\ - if (status != 0)\ - goto irq_err;\ - } while (0); - struct adis16255_init_data *init_data = spi->dev.platform_data; struct spi_adis16255_data *spiadis; int status = 0; - u16 value; spiadis = kzalloc(sizeof(*spiadis), GFP_KERNEL); if (!spiadis) return -ENOMEM; spiadis->spi = spi; - spiadis->irq_adis = init_data->irq; spiadis->direction = init_data->direction; if (init_data->negative) spiadis->negative = 1; - status = gpio_request(spiadis->irq_adis, "adis16255"); + status = gpio_request(init_data->irq, "adis16255"); if (status != 0) goto err; - status = gpio_direction_input(spiadis->irq_adis); + status = gpio_direction_input(init_data->irq); if (status != 0) goto gpio_err; - spiadis->irq = gpio_to_irq(spiadis->irq_adis); + spiadis->irq = gpio_to_irq(init_data->irq); status = request_threaded_irq(spiadis->irq, NULL, adis_irq_thread, @@ -307,50 +397,25 @@ static int spi_adis16255_probe(struct spi_device *spi) 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"); - - 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)); - - 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); + status = sysfs_create_group(&spi->dev.kobj, &adis16255_attr_group); + if (status != 0) + goto irq_err; - /* timebase = 1.953 ms, Ns = 0 -> 512 Hz sample rate */ - value = 0x0001; - AD_CHK(spi_adis16255_write_data(spiadis, - ADIS_SMPL_PRD_MSB, ADIS_SMPL_PRD_LSB, - (u8 *)&value)); - value = 0x0000; - AD_CHK(spi_adis16255_read_data(spiadis, ADIS_SMPL_PRD_MSB, - (u8 *)&value)); - dev_info(&spi->dev, "adis SMP_PRD is %.4x\n", value); + status = spi_adis16255_bringup(spiadis); + if (status != 0) + goto irq_err; - /* set interrupt on new data... */ - value = 0x0006; - AD_CHK(spi_adis16255_write_data(spiadis, - ADIS_MSC_CTRL_MSB, ADIS_MSC_CTRL_LSB, - (u8 *)&value)); - value = 0x0000; - 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; @@ -362,11 +427,8 @@ static int spi_adis16255_remove(struct spi_device *spi) spi_adis16255_shutdown(spiadis); - dev_info(&spi->dev, "unregister: GPIO %d IRQ %d\n", - spiadis->irq_adis, spiadis->irq); - 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); -- motzblog.wordpress.com _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/devel