linux/drivers/staging/iio/frequency/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#include <linux/module.h>
  18
  19#include <linux/iio/iio.h>
  20#include <linux/iio/sysfs.h>
  21
  22#define DRV_NAME "ad5930"
  23
  24#define value_mask (u16)0xf000
  25#define addr_shift 12
  26
  27/* Register format: 4 bits addr + 12 bits value */
  28struct ad5903_config {
  29        u16 control;
  30        u16 incnum;
  31        u16 frqdelt[2];
  32        u16 incitvl;
  33        u16 buritvl;
  34        u16 strtfrq[2];
  35};
  36
  37struct ad5930_state {
  38        struct mutex lock;
  39        struct spi_device *sdev;
  40};
  41
  42static ssize_t ad5930_set_parameter(struct device *dev,
  43                                        struct device_attribute *attr,
  44                                        const char *buf,
  45                                        size_t len)
  46{
  47        struct spi_transfer xfer;
  48        int ret;
  49        struct ad5903_config *config = (struct ad5903_config *)buf;
  50        struct iio_dev *idev = dev_to_iio_dev(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        ret = spi_sync_transfer(st->sdev, &xfer, 1);
  67        if (ret)
  68                goto error_ret;
  69error_ret:
  70        mutex_unlock(&st->lock);
  71
  72        return ret ? ret : len;
  73}
  74
  75static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad5930_set_parameter, 0);
  76
  77static struct attribute *ad5930_attributes[] = {
  78        &iio_dev_attr_dds.dev_attr.attr,
  79        NULL,
  80};
  81
  82static const struct attribute_group ad5930_attribute_group = {
  83        .attrs = ad5930_attributes,
  84};
  85
  86static const struct iio_info ad5930_info = {
  87        .attrs = &ad5930_attribute_group,
  88        .driver_module = THIS_MODULE,
  89};
  90
  91static int ad5930_probe(struct spi_device *spi)
  92{
  93        struct ad5930_state *st;
  94        struct iio_dev *idev;
  95        int ret = 0;
  96
  97        idev = iio_device_alloc(sizeof(*st));
  98        if (idev == NULL) {
  99                ret = -ENOMEM;
 100                goto error_ret;
 101        }
 102        spi_set_drvdata(spi, idev);
 103        st = iio_priv(idev);
 104
 105        mutex_init(&st->lock);
 106        st->sdev = spi;
 107        idev->dev.parent = &spi->dev;
 108        idev->info = &ad5930_info;
 109        idev->modes = INDIO_DIRECT_MODE;
 110
 111        ret = iio_device_register(idev);
 112        if (ret)
 113                goto error_free_dev;
 114        spi->max_speed_hz = 2000000;
 115        spi->mode = SPI_MODE_3;
 116        spi->bits_per_word = 16;
 117        spi_setup(spi);
 118
 119        return 0;
 120
 121error_free_dev:
 122        iio_device_free(idev);
 123error_ret:
 124        return ret;
 125}
 126
 127static int ad5930_remove(struct spi_device *spi)
 128{
 129        iio_device_unregister(spi_get_drvdata(spi));
 130        iio_device_free(spi_get_drvdata(spi));
 131
 132        return 0;
 133}
 134
 135static struct spi_driver ad5930_driver = {
 136        .driver = {
 137                .name = DRV_NAME,
 138                .owner = THIS_MODULE,
 139        },
 140        .probe = ad5930_probe,
 141        .remove = ad5930_remove,
 142};
 143module_spi_driver(ad5930_driver);
 144
 145MODULE_AUTHOR("Cliff Cai");
 146MODULE_DESCRIPTION("Analog Devices ad5930 driver");
 147MODULE_LICENSE("GPL v2");
 148MODULE_ALIAS("spi:" DRV_NAME);
 149