Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
[pandora-kernel.git] / drivers / staging / adis16255 / adis16255.c
index 8d11069..55d66e2 100644 (file)
  * 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>
  * @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,135 +236,199 @@ 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;
+               }
+       }
+
+       /* 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;
+}
 
-#define AD_CHK(_ss)\
-       do {\
-               status ÿss;\
-               if (status !ð)\
-                       goto irq_err;\
-       } while (0);
+/*-------------------------------------------------------------------------*/
+
+static int __devinit spi_adis16255_probe(struct spi_device *spi)
+{
 
-       struct adis16255_init_data *init_data ÿpi->dev.platform_data;
+       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;
 }
 
-static int spi_adis16255_remove(struct spi_device *spi)
+static int __devexit 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),
 };
 
 /*-------------------------------------------------------------------------*/