linux/drivers/staging/iio/dds/ad9951.c
<<
>>
Prefs
   1/*
   2 * Driver for ADI Direct Digital Synthesis ad9951
   3 *
   4 * Copyright (c) 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 "ad9951"
  22
  23#define CFR1 0x0
  24#define CFR2 0x1
  25
  26#define AUTO_OSK        (1)
  27#define OSKEN           (1 << 1)
  28#define LOAD_ARR        (1 << 2)
  29
  30#define AUTO_SYNC       (1 << 7)
  31
  32#define LSB_FST         (1)
  33#define SDIO_IPT        (1 << 1)
  34#define CLR_PHA         (1 << 2)
  35#define SINE_OPT        (1 << 4)
  36#define ACLR_PHA        (1 << 5)
  37
  38#define VCO_RANGE       (1 << 2)
  39
  40#define CRS_OPT         (1 << 1)
  41#define HMANU_SYNC      (1 << 2)
  42#define HSPD_SYNC       (1 << 3)
  43
  44/* Register format: 1 byte addr + value */
  45struct ad9951_config {
  46        u8 asf[3];
  47        u8 arr[2];
  48        u8 ftw0[5];
  49        u8 ftw1[3];
  50};
  51
  52struct ad9951_state {
  53        struct mutex lock;
  54        struct spi_device *sdev;
  55};
  56
  57static ssize_t ad9951_set_parameter(struct device *dev,
  58                                        struct device_attribute *attr,
  59                                        const char *buf,
  60                                        size_t len)
  61{
  62        struct spi_message msg;
  63        struct spi_transfer xfer;
  64        int ret;
  65        struct ad9951_config *config = (struct ad9951_config *)buf;
  66        struct iio_dev *idev = dev_get_drvdata(dev);
  67        struct ad9951_state *st = iio_priv(idev);
  68
  69        xfer.len = 3;
  70        xfer.tx_buf = &config->asf[0];
  71        mutex_lock(&st->lock);
  72
  73        spi_message_init(&msg);
  74        spi_message_add_tail(&xfer, &msg);
  75        ret = spi_sync(st->sdev, &msg);
  76        if (ret)
  77                goto error_ret;
  78
  79        xfer.len = 2;
  80        xfer.tx_buf = &config->arr[0];
  81
  82        spi_message_init(&msg);
  83        spi_message_add_tail(&xfer, &msg);
  84        ret = spi_sync(st->sdev, &msg);
  85        if (ret)
  86                goto error_ret;
  87
  88        xfer.len = 5;
  89        xfer.tx_buf = &config->ftw0[0];
  90
  91        spi_message_init(&msg);
  92        spi_message_add_tail(&xfer, &msg);
  93        ret = spi_sync(st->sdev, &msg);
  94        if (ret)
  95                goto error_ret;
  96
  97        xfer.len = 3;
  98        xfer.tx_buf = &config->ftw1[0];
  99
 100        spi_message_init(&msg);
 101        spi_message_add_tail(&xfer, &msg);
 102        ret = spi_sync(st->sdev, &msg);
 103        if (ret)
 104                goto error_ret;
 105error_ret:
 106        mutex_unlock(&st->lock);
 107
 108        return ret ? ret : len;
 109}
 110
 111static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9951_set_parameter, 0);
 112
 113static void ad9951_init(struct ad9951_state *st)
 114{
 115        struct spi_message msg;
 116        struct spi_transfer xfer;
 117        int ret;
 118        u8 cfr[5];
 119
 120        cfr[0] = CFR1;
 121        cfr[1] = 0;
 122        cfr[2] = LSB_FST | CLR_PHA | SINE_OPT | ACLR_PHA;
 123        cfr[3] = AUTO_OSK | OSKEN | LOAD_ARR;
 124        cfr[4] = 0;
 125
 126        mutex_lock(&st->lock);
 127
 128        xfer.len = 5;
 129        xfer.tx_buf = &cfr;
 130
 131        spi_message_init(&msg);
 132        spi_message_add_tail(&xfer, &msg);
 133        ret = spi_sync(st->sdev, &msg);
 134        if (ret)
 135                goto error_ret;
 136
 137        cfr[0] = CFR2;
 138        cfr[1] = VCO_RANGE;
 139        cfr[2] = HSPD_SYNC;
 140        cfr[3] = 0;
 141
 142        xfer.len = 4;
 143        xfer.tx_buf = &cfr;
 144
 145        spi_message_init(&msg);
 146        spi_message_add_tail(&xfer, &msg);
 147        ret = spi_sync(st->sdev, &msg);
 148        if (ret)
 149                goto error_ret;
 150
 151error_ret:
 152        mutex_unlock(&st->lock);
 153
 154
 155
 156}
 157
 158static struct attribute *ad9951_attributes[] = {
 159        &iio_dev_attr_dds.dev_attr.attr,
 160        NULL,
 161};
 162
 163static const struct attribute_group ad9951_attribute_group = {
 164        .name = DRV_NAME,
 165        .attrs = ad9951_attributes,
 166};
 167
 168static const struct iio_info ad9951_info = {
 169        .attrs = &ad9951_attribute_group,
 170        .driver_module = THIS_MODULE,
 171};
 172
 173static int __devinit ad9951_probe(struct spi_device *spi)
 174{
 175        struct ad9951_state *st;
 176        struct iio_dev *idev;
 177        int ret = 0;
 178
 179        idev = iio_allocate_device(sizeof(*st));
 180        if (idev == NULL) {
 181                ret = -ENOMEM;
 182                goto error_ret;
 183        }
 184        spi_set_drvdata(spi, idev);
 185        st = iio_priv(idev);
 186        mutex_init(&st->lock);
 187        st->sdev = spi;
 188
 189        idev->dev.parent = &spi->dev;
 190
 191        idev->info = &ad9951_info;
 192        idev->modes = INDIO_DIRECT_MODE;
 193
 194        ret = iio_device_register(idev);
 195        if (ret)
 196                goto error_free_dev;
 197        spi->max_speed_hz = 2000000;
 198        spi->mode = SPI_MODE_3;
 199        spi->bits_per_word = 8;
 200        spi_setup(spi);
 201        ad9951_init(st);
 202        return 0;
 203
 204error_free_dev:
 205        iio_free_device(idev);
 206
 207error_ret:
 208        return ret;
 209}
 210
 211static int __devexit ad9951_remove(struct spi_device *spi)
 212{
 213        iio_device_unregister(spi_get_drvdata(spi));
 214
 215        return 0;
 216}
 217
 218static struct spi_driver ad9951_driver = {
 219        .driver = {
 220                .name = DRV_NAME,
 221                .owner = THIS_MODULE,
 222        },
 223        .probe = ad9951_probe,
 224        .remove = __devexit_p(ad9951_remove),
 225};
 226
 227static __init int ad9951_spi_init(void)
 228{
 229        return spi_register_driver(&ad9951_driver);
 230}
 231module_init(ad9951_spi_init);
 232
 233static __exit void ad9951_spi_exit(void)
 234{
 235        spi_unregister_driver(&ad9951_driver);
 236}
 237module_exit(ad9951_spi_exit);
 238
 239MODULE_AUTHOR("Cliff Cai");
 240MODULE_DESCRIPTION("Analog Devices ad9951 driver");
 241MODULE_LICENSE("GPL v2");
 242