linux/drivers/staging/iio/dds/ad5930.c
<<
>>
Prefs
   1/*
   2 * Driver for ADI Direct Digital Synthesis ad5930
   3 *
   4 * Copyright (c) 2010-2010 Analog Devices Inc.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 */
  11#include <linux/types.h>
  12#include <linux/mutex.h>
  13#include <linux/device.h>
  14#include <linux/spi/spi.h>
  15#include <linux/slab.h>
  16#include <linux/sysfs.h>
  17
  18#include "../iio.h"
  19#include "../sysfs.h"
  20
  21#define DRV_NAME "ad5930"
  22
  23#define value_mask (u16)0xf000
  24#define addr_shift 12
  25
  26/* Register format: 4 bits addr + 12 bits value */
  27struct ad5903_config {
  28        u16 control;
  29        u16 incnum;
  30        u16 frqdelt[2];
  31        u16 incitvl;
  32        u16 buritvl;
  33        u16 strtfrq[2];
  34};
  35
  36struct ad5930_state {
  37        struct mutex lock;
  38        struct spi_device *sdev;
  39};
  40
  41static ssize_t ad5930_set_parameter(struct device *dev,
  42                                        struct device_attribute *attr,
  43                                        const char *buf,
  44                                        size_t len)
  45{
  46        struct spi_message msg;
  47        struct spi_transfer xfer;
  48        int ret;
  49        struct ad5903_config *config = (struct ad5903_config *)buf;
  50        struct iio_dev *idev = dev_get_drvdata(dev);
  51        struct ad5930_state *st = iio_priv(idev);
  52
  53        config->control = (config->control & ~value_mask);
  54        config->incnum = (config->control & ~value_mask) | (1 << addr_shift);
  55        config->frqdelt[0] = (config->control & ~value_mask) | (2 << addr_shift);
  56        config->frqdelt[1] = (config->control & ~value_mask) | 3 << addr_shift;
  57        config->incitvl = (config->control & ~value_mask) | 4 << addr_shift;
  58        config->buritvl = (config->control & ~value_mask) | 8 << addr_shift;
  59        config->strtfrq[0] = (config->control & ~value_mask) | 0xc << addr_shift;
  60        config->strtfrq[1] = (config->control & ~value_mask) | 0xd << addr_shift;
  61
  62        xfer.len = len;
  63        xfer.tx_buf = config;
  64        mutex_lock(&st->lock);
  65
  66        spi_message_init(&msg);
  67        spi_message_add_tail(&xfer, &msg);
  68        ret = spi_sync(st->sdev, &msg);
  69        if (ret)
  70                goto error_ret;
  71error_ret:
  72        mutex_unlock(&st->lock);
  73
  74        return ret ? ret : len;
  75}
  76
  77static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad5930_set_parameter, 0);
  78
  79static struct attribute *ad5930_attributes[] = {
  80        &iio_dev_attr_dds.dev_attr.attr,
  81        NULL,
  82};
  83
  84static const struct attribute_group ad5930_attribute_group = {
  85        .attrs = ad5930_attributes,
  86};
  87
  88static const struct iio_info ad5930_info = {
  89        .attrs = &ad5930_attribute_group,
  90        .driver_module = THIS_MODULE,
  91};
  92
  93static int __devinit ad5930_probe(struct spi_device *spi)
  94{
  95        struct ad5930_state *st;
  96        struct iio_dev *idev;
  97        int ret = 0;
  98
  99        idev = iio_allocate_device(sizeof(*st));
 100        if (idev == NULL) {
 101                ret = -ENOMEM;
 102                goto error_ret;
 103        }
 104        spi_set_drvdata(spi, idev);
 105        st = iio_priv(idev);
 106
 107        mutex_init(&st->lock);
 108        st->sdev = spi;
 109        idev->dev.parent = &spi->dev;
 110        idev->info = &ad5930_info;
 111        idev->modes = INDIO_DIRECT_MODE;
 112
 113        ret = iio_device_register(idev);
 114        if (ret)
 115                goto error_free_dev;
 116        spi->max_speed_hz = 2000000;
 117        spi->mode = SPI_MODE_3;
 118        spi->bits_per_word = 16;
 119        spi_setup(spi);
 120
 121        return 0;
 122
 123error_free_dev:
 124        iio_free_device(idev);
 125error_ret:
 126        return ret;
 127}
 128
 129static int __devexit ad5930_remove(struct spi_device *spi)
 130{
 131        iio_device_unregister(spi_get_drvdata(spi));
 132
 133        return 0;
 134}
 135
 136static struct spi_driver ad5930_driver = {
 137        .driver = {
 138                .name = DRV_NAME,
 139                .owner = THIS_MODULE,
 140        },
 141        .probe = ad5930_probe,
 142        .remove = __devexit_p(ad5930_remove),
 143};
 144
 145static __init int ad5930_spi_init(void)
 146{
 147        return spi_register_driver(&ad5930_driver);
 148}
 149module_init(ad5930_spi_init);
 150
 151static __exit void ad5930_spi_exit(void)
 152{
 153        spi_unregister_driver(&ad5930_driver);
 154}
 155module_exit(ad5930_spi_exit);
 156
 157MODULE_AUTHOR("Cliff Cai");
 158MODULE_DESCRIPTION("Analog Devices ad5930 driver");
 159MODULE_LICENSE("GPL v2");
 160