linux/drivers/staging/iio/accel/kxsd9.c
<<
>>
Prefs
   1/*
   2 * kxsd9.c      simple support for the Kionix KXSD9 3D
   3 *              accelerometer.
   4 *
   5 * Copyright (c) 2008-2009 Jonathan Cameron <jic23@cam.ac.uk>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * The i2c interface is very similar, so shouldn't be a problem once
  12 * I have a suitable wire made up.
  13 *
  14 * TODO:        Support the motion detector
  15 *              Uses register address incrementing so could have a
  16 *              heavily optimized ring buffer access function.
  17 */
  18
  19#include <linux/device.h>
  20#include <linux/kernel.h>
  21#include <linux/spi/spi.h>
  22#include <linux/sysfs.h>
  23#include <linux/slab.h>
  24
  25#include "../iio.h"
  26#include "../sysfs.h"
  27#include "../adc/adc.h"
  28#include "accel.h"
  29
  30#define KXSD9_REG_X             0x00
  31#define KXSD9_REG_Y             0x02
  32#define KXSD9_REG_Z             0x04
  33#define KXSD9_REG_AUX           0x06
  34#define KXSD9_REG_RESET         0x0a
  35#define KXSD9_REG_CTRL_C        0x0c
  36
  37#define KXSD9_FS_8              0x00
  38#define KXSD9_FS_6              0x01
  39#define KXSD9_FS_4              0x02
  40#define KXSD9_FS_2              0x03
  41#define KXSD9_FS_MASK           0x03
  42
  43#define KXSD9_REG_CTRL_B        0x0d
  44#define KXSD9_REG_CTRL_A        0x0e
  45
  46#define KXSD9_READ(a) (0x80 | (a))
  47#define KXSD9_WRITE(a) (a)
  48
  49#define KXSD9_SCALE_2G "0.011978"
  50#define KXSD9_SCALE_4G "0.023927"
  51#define KXSD9_SCALE_6G "0.035934"
  52#define KXSD9_SCALE_8G "0.047853"
  53
  54#define KXSD9_STATE_RX_SIZE 2
  55#define KXSD9_STATE_TX_SIZE 4
  56/**
  57 * struct kxsd9_state - device related storage
  58 * @buf_lock:   protect the rx and tx buffers.
  59 * @indio_dev:  associated industrial IO device
  60 * @us:         spi device
  61 * @rx:         single rx buffer storage
  62 * @tx:         single tx buffer storage
  63 **/
  64struct kxsd9_state {
  65        struct mutex buf_lock;
  66        struct iio_dev *indio_dev;
  67        struct spi_device *us;
  68        u8 *rx;
  69        u8 *tx;
  70};
  71
  72/* This may want to move to mili g to allow for non integer ranges */
  73static ssize_t kxsd9_read_scale(struct device *dev,
  74                                struct device_attribute *attr,
  75                                char *buf)
  76{
  77        int ret;
  78        ssize_t len = 0;
  79        struct iio_dev *indio_dev = dev_get_drvdata(dev);
  80        struct kxsd9_state *st = indio_dev->dev_data;
  81        struct spi_transfer xfer = {
  82                .bits_per_word = 8,
  83                .len = 2,
  84                .cs_change = 1,
  85                .tx_buf = st->tx,
  86                .rx_buf = st->rx,
  87        };
  88        struct spi_message msg;
  89
  90        mutex_lock(&st->buf_lock);
  91        st->tx[0] = KXSD9_READ(KXSD9_REG_CTRL_C);
  92        st->tx[1] = 0;
  93        spi_message_init(&msg);
  94        spi_message_add_tail(&xfer, &msg);
  95        ret = spi_sync(st->us, &msg);
  96        if (ret)
  97                goto error_ret;
  98
  99        switch (st->rx[1] & KXSD9_FS_MASK) {
 100        case KXSD9_FS_8:
 101                len += sprintf(buf, "%s\n", KXSD9_SCALE_8G);
 102                break;
 103        case KXSD9_FS_6:
 104                len += sprintf(buf, "%s\n", KXSD9_SCALE_6G);
 105                break;
 106        case KXSD9_FS_4:
 107                len += sprintf(buf, "%s\n", KXSD9_SCALE_4G);
 108                break;
 109        case KXSD9_FS_2:
 110                len += sprintf(buf, "%s\n", KXSD9_SCALE_2G);
 111                break;
 112        }
 113
 114error_ret:
 115        mutex_unlock(&st->buf_lock);
 116
 117        return ret ? ret : len;
 118}
 119static ssize_t kxsd9_write_scale(struct device *dev,
 120                                 struct device_attribute *attr,
 121                                 const char *buf,
 122                                 size_t len)
 123{
 124
 125        struct spi_message msg;
 126        int ret;
 127        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 128        struct kxsd9_state *st = indio_dev->dev_data;
 129        u8 val;
 130        struct spi_transfer xfers[] = {
 131                {
 132                        .bits_per_word = 8,
 133                        .len = 2,
 134                        .cs_change = 1,
 135                        .tx_buf = st->tx,
 136                        .rx_buf = st->rx,
 137                }, {
 138                        .bits_per_word = 8,
 139                        .len = 2,
 140                        .cs_change = 1,
 141                        .tx_buf = st->tx,
 142                },
 143        };
 144
 145        if (!strncmp(buf, KXSD9_SCALE_8G,
 146                     strlen(buf) < strlen(KXSD9_SCALE_8G)
 147                     ? strlen(buf) : strlen(KXSD9_SCALE_8G)))
 148                val = KXSD9_FS_8;
 149        else if (!strncmp(buf, KXSD9_SCALE_6G,
 150                          strlen(buf) < strlen(KXSD9_SCALE_6G)
 151                          ? strlen(buf) : strlen(KXSD9_SCALE_6G)))
 152                val = KXSD9_FS_6;
 153        else if (!strncmp(buf, KXSD9_SCALE_4G,
 154                          strlen(buf) < strlen(KXSD9_SCALE_4G)
 155                          ? strlen(buf) : strlen(KXSD9_SCALE_4G)))
 156                val = KXSD9_FS_4;
 157        else if (!strncmp(buf, KXSD9_SCALE_2G,
 158                          strlen(buf) < strlen(KXSD9_SCALE_2G)
 159                          ? strlen(buf) : strlen(KXSD9_SCALE_2G)))
 160                val = KXSD9_FS_2;
 161        else
 162                return -EINVAL;
 163
 164        mutex_lock(&st->buf_lock);
 165        st->tx[0] = KXSD9_READ(KXSD9_REG_CTRL_C);
 166        st->tx[1] = 0;
 167        spi_message_init(&msg);
 168        spi_message_add_tail(&xfers[0], &msg);
 169        ret = spi_sync(st->us, &msg);
 170        if (ret)
 171                goto error_ret;
 172        st->tx[0] = KXSD9_WRITE(KXSD9_REG_CTRL_C);
 173        st->tx[1] = (st->rx[1] & ~KXSD9_FS_MASK) | val;
 174
 175        spi_message_init(&msg);
 176        spi_message_add_tail(&xfers[1], &msg);
 177        ret = spi_sync(st->us, &msg);
 178error_ret:
 179        mutex_unlock(&st->buf_lock);
 180        return ret ? ret : len;
 181}
 182
 183static ssize_t kxsd9_read_accel(struct device *dev,
 184                                struct device_attribute *attr,
 185                                char *buf)
 186{
 187        struct spi_message msg;
 188        int ret;
 189        ssize_t len = 0;
 190        u16 val;
 191        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 192        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 193        struct kxsd9_state *st = indio_dev->dev_data;
 194        struct spi_transfer xfers[] = {
 195                {
 196                        .bits_per_word = 8,
 197                        .len = 1,
 198                        .cs_change = 0,
 199                        .delay_usecs = 200,
 200                        .tx_buf = st->tx,
 201                }, {
 202                        .bits_per_word = 8,
 203                        .len = 2,
 204                        .cs_change = 1,
 205                        .rx_buf = st->rx,
 206                },
 207        };
 208
 209        mutex_lock(&st->buf_lock);
 210        st->tx[0] = KXSD9_READ(this_attr->address);
 211        spi_message_init(&msg);
 212        spi_message_add_tail(&xfers[0], &msg);
 213        spi_message_add_tail(&xfers[1], &msg);
 214        ret = spi_sync(st->us, &msg);
 215        if (ret)
 216                goto error_ret;
 217        val = (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0);
 218        len = sprintf(buf, "%d\n", val);
 219error_ret:
 220        mutex_unlock(&st->buf_lock);
 221
 222        return ret ? ret : len;
 223}
 224
 225static IIO_DEV_ATTR_ACCEL_X(kxsd9_read_accel, KXSD9_REG_X);
 226static IIO_DEV_ATTR_ACCEL_Y(kxsd9_read_accel, KXSD9_REG_Y);
 227static IIO_DEV_ATTR_ACCEL_Z(kxsd9_read_accel, KXSD9_REG_Z);
 228static IIO_DEV_ATTR_IN_RAW(0, kxsd9_read_accel, KXSD9_REG_AUX);
 229
 230static IIO_DEVICE_ATTR(accel_scale,
 231                S_IRUGO | S_IWUSR,
 232                kxsd9_read_scale,
 233                kxsd9_write_scale,
 234                0);
 235
 236static IIO_CONST_ATTR(accel_scale_available,
 237                KXSD9_SCALE_2G " "
 238                KXSD9_SCALE_4G " "
 239                KXSD9_SCALE_6G " "
 240                KXSD9_SCALE_8G);
 241
 242static struct attribute *kxsd9_attributes[] = {
 243        &iio_dev_attr_accel_x_raw.dev_attr.attr,
 244        &iio_dev_attr_accel_y_raw.dev_attr.attr,
 245        &iio_dev_attr_accel_z_raw.dev_attr.attr,
 246        &iio_dev_attr_in0_raw.dev_attr.attr,
 247        &iio_dev_attr_accel_scale.dev_attr.attr,
 248        &iio_const_attr_accel_scale_available.dev_attr.attr,
 249        NULL,
 250};
 251
 252static const struct attribute_group kxsd9_attribute_group = {
 253        .attrs = kxsd9_attributes,
 254};
 255
 256static int __devinit kxsd9_power_up(struct spi_device *spi)
 257{
 258        int ret;
 259        struct spi_transfer xfers[2] = {
 260                {
 261                        .bits_per_word = 8,
 262                        .len = 2,
 263                        .cs_change = 1,
 264                }, {
 265                        .bits_per_word = 8,
 266                        .len = 2,
 267                        .cs_change = 1,
 268                },
 269        };
 270        struct spi_message msg;
 271        u8 *tx2;
 272        u8 *tx = kmalloc(2, GFP_KERNEL);
 273
 274        if (tx == NULL) {
 275                ret = -ENOMEM;
 276                goto error_ret;
 277        }
 278        tx2 = kmalloc(2, GFP_KERNEL);
 279        if (tx2 == NULL) {
 280                ret = -ENOMEM;
 281                goto error_free_tx;
 282        }
 283        tx[0] = 0x0d;
 284        tx[1] = 0x40;
 285
 286        tx2[0] = 0x0c;
 287        tx2[1] = 0x9b;
 288
 289        xfers[0].tx_buf = tx;
 290        xfers[1].tx_buf = tx2;
 291        spi_message_init(&msg);
 292        spi_message_add_tail(&xfers[0], &msg);
 293        spi_message_add_tail(&xfers[1], &msg);
 294        ret = spi_sync(spi, &msg);
 295
 296        kfree(tx2);
 297error_free_tx:
 298        kfree(tx);
 299error_ret:
 300        return ret;
 301
 302};
 303
 304static int __devinit kxsd9_probe(struct spi_device *spi)
 305{
 306
 307        struct kxsd9_state *st;
 308        int ret = 0;
 309
 310        st = kzalloc(sizeof(*st), GFP_KERNEL);
 311        if (st == NULL) {
 312                ret = -ENOMEM;
 313                goto error_ret;
 314        }
 315        spi_set_drvdata(spi, st);
 316
 317        st->rx = kmalloc(sizeof(*st->rx)*KXSD9_STATE_RX_SIZE,
 318                         GFP_KERNEL);
 319        if (st->rx == NULL) {
 320                ret = -ENOMEM;
 321                goto error_free_st;
 322        }
 323        st->tx = kmalloc(sizeof(*st->tx)*KXSD9_STATE_TX_SIZE,
 324                         GFP_KERNEL);
 325        if (st->tx == NULL) {
 326                ret = -ENOMEM;
 327                goto error_free_rx;
 328        }
 329
 330        st->us = spi;
 331        mutex_init(&st->buf_lock);
 332        st->indio_dev = iio_allocate_device();
 333        if (st->indio_dev == NULL) {
 334                ret = -ENOMEM;
 335                goto error_free_tx;
 336        }
 337        st->indio_dev->dev.parent = &spi->dev;
 338        /* for now */
 339        st->indio_dev->num_interrupt_lines = 0;
 340        st->indio_dev->event_attrs = NULL;
 341
 342        st->indio_dev->attrs = &kxsd9_attribute_group;
 343        st->indio_dev->dev_data = (void *)(st);
 344        st->indio_dev->driver_module = THIS_MODULE;
 345        st->indio_dev->modes = INDIO_DIRECT_MODE;
 346
 347        ret = iio_device_register(st->indio_dev);
 348        if (ret)
 349                goto error_free_dev;
 350
 351        spi->mode = SPI_MODE_0;
 352        spi_setup(spi);
 353        kxsd9_power_up(spi);
 354
 355        return 0;
 356
 357error_free_dev:
 358        iio_free_device(st->indio_dev);
 359error_free_tx:
 360        kfree(st->tx);
 361error_free_rx:
 362        kfree(st->rx);
 363error_free_st:
 364        kfree(st);
 365error_ret:
 366        return ret;
 367}
 368
 369static int __devexit kxsd9_remove(struct spi_device *spi)
 370{
 371        struct kxsd9_state *st = spi_get_drvdata(spi);
 372
 373        iio_device_unregister(st->indio_dev);
 374        kfree(st->tx);
 375        kfree(st->rx);
 376        kfree(st);
 377
 378        return 0;
 379}
 380
 381static struct spi_driver kxsd9_driver = {
 382        .driver = {
 383                .name = "kxsd9",
 384                .owner = THIS_MODULE,
 385        },
 386        .probe = kxsd9_probe,
 387        .remove = __devexit_p(kxsd9_remove),
 388};
 389
 390static __init int kxsd9_spi_init(void)
 391{
 392        return spi_register_driver(&kxsd9_driver);
 393}
 394module_init(kxsd9_spi_init);
 395
 396static __exit void kxsd9_spi_exit(void)
 397{
 398        spi_unregister_driver(&kxsd9_driver);
 399}
 400module_exit(kxsd9_spi_exit);
 401
 402MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
 403MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
 404MODULE_LICENSE("GPL v2");
 405