linux/drivers/staging/iio/frequency/ad9910.c
<<
>>
Prefs
   1/*
   2 * Driver for ADI Direct Digital Synthesis ad9910
   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#include <linux/module.h>
  18
  19#include <linux/iio/iio.h>
  20#include <linux/iio/sysfs.h>
  21
  22#define DRV_NAME "ad9910"
  23
  24#define CFR1 0x0
  25#define CFR2 0x1
  26#define CFR3 0x2
  27
  28#define AUXDAC 0x3
  29#define IOUPD 0x4
  30#define FTW 0x7
  31#define POW 0x8
  32#define ASF 0x9
  33#define MULTC 0x0A
  34#define DIG_RAMPL 0x0B
  35#define DIG_RAMPS 0x0C
  36#define DIG_RAMPR 0x0D
  37#define SIN_TONEP0 0x0E
  38#define SIN_TONEP1 0x0F
  39#define SIN_TONEP2 0x10
  40#define SIN_TONEP3 0x11
  41#define SIN_TONEP4 0x12
  42#define SIN_TONEP5 0x13
  43#define SIN_TONEP6 0x14
  44#define SIN_TONEP7 0x15
  45
  46#define RAM_ENABLE      (1 << 7)
  47
  48#define MANUAL_OSK      (1 << 7)
  49#define INVSIC          (1 << 6)
  50#define DDS_SINEOP      (1)
  51
  52#define AUTO_OSK        (1)
  53#define OSKEN           (1 << 1)
  54#define LOAD_ARR        (1 << 2)
  55#define CLR_PHA         (1 << 3)
  56#define CLR_DIG         (1 << 4)
  57#define ACLR_PHA        (1 << 5)
  58#define ACLR_DIG        (1 << 6)
  59#define LOAD_LRR        (1 << 7)
  60
  61#define LSB_FST         (1)
  62#define SDIO_IPT        (1 << 1)
  63#define EXT_PWD         (1 << 3)
  64#define ADAC_PWD        (1 << 4)
  65#define REFCLK_PWD      (1 << 5)
  66#define DAC_PWD         (1 << 6)
  67#define DIG_PWD         (1 << 7)
  68
  69#define ENA_AMP         (1)
  70#define READ_FTW        (1)
  71#define DIGR_LOW        (1 << 1)
  72#define DIGR_HIGH       (1 << 2)
  73#define DIGR_ENA        (1 << 3)
  74#define SYNCCLK_ENA     (1 << 6)
  75#define ITER_IOUPD      (1 << 7)
  76
  77#define TX_ENA          (1 << 1)
  78#define PDCLK_INV       (1 << 2)
  79#define PDCLK_ENB       (1 << 3)
  80
  81#define PARA_ENA        (1 << 4)
  82#define SYNC_DIS        (1 << 5)
  83#define DATA_ASS        (1 << 6)
  84#define MATCH_ENA       (1 << 7)
  85
  86#define PLL_ENA         (1)
  87#define PFD_RST         (1 << 2)
  88#define REFCLK_RST      (1 << 6)
  89#define REFCLK_BYP      (1 << 7)
  90
  91/* Register format: 1 byte addr + value */
  92struct ad9910_config {
  93        u8 auxdac[5];
  94        u8 ioupd[5];
  95        u8 ftw[5];
  96        u8 pow[3];
  97        u8 asf[5];
  98        u8 multc[5];
  99        u8 dig_rampl[9];
 100        u8 dig_ramps[9];
 101        u8 dig_rampr[5];
 102        u8 sin_tonep0[9];
 103        u8 sin_tonep1[9];
 104        u8 sin_tonep2[9];
 105        u8 sin_tonep3[9];
 106        u8 sin_tonep4[9];
 107        u8 sin_tonep5[9];
 108        u8 sin_tonep6[9];
 109        u8 sin_tonep7[9];
 110};
 111
 112struct ad9910_state {
 113        struct mutex lock;
 114        struct spi_device *sdev;
 115};
 116
 117static ssize_t ad9910_set_parameter(struct device *dev,
 118                                        struct device_attribute *attr,
 119                                        const char *buf,
 120                                        size_t len)
 121{
 122        struct spi_transfer xfer;
 123        int ret;
 124        struct ad9910_config *config = (struct ad9910_config *)buf;
 125        struct iio_dev *idev = dev_to_iio_dev(dev);
 126        struct ad9910_state *st = iio_priv(idev);
 127
 128        xfer.len = 5;
 129        xfer.tx_buf = &config->auxdac[0];
 130        mutex_lock(&st->lock);
 131
 132        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 133        if (ret)
 134                goto error_ret;
 135
 136        xfer.len = 5;
 137        xfer.tx_buf = &config->ioupd[0];
 138
 139        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 140        if (ret)
 141                goto error_ret;
 142
 143        xfer.len = 5;
 144        xfer.tx_buf = &config->ftw[0];
 145
 146        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 147        if (ret)
 148                goto error_ret;
 149
 150        xfer.len = 3;
 151        xfer.tx_buf = &config->pow[0];
 152
 153        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 154        if (ret)
 155                goto error_ret;
 156
 157        xfer.len = 5;
 158        xfer.tx_buf = &config->asf[0];
 159
 160        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 161        if (ret)
 162                goto error_ret;
 163
 164        xfer.len = 5;
 165        xfer.tx_buf = &config->multc[0];
 166
 167        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 168        if (ret)
 169                goto error_ret;
 170
 171        xfer.len = 9;
 172        xfer.tx_buf = &config->dig_rampl[0];
 173
 174        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 175        if (ret)
 176                goto error_ret;
 177
 178        xfer.len = 9;
 179        xfer.tx_buf = &config->dig_ramps[0];
 180
 181        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 182        if (ret)
 183                goto error_ret;
 184
 185        xfer.len = 5;
 186        xfer.tx_buf = &config->dig_rampr[0];
 187
 188        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 189        if (ret)
 190                goto error_ret;
 191
 192        xfer.len = 9;
 193        xfer.tx_buf = &config->sin_tonep0[0];
 194
 195        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 196        if (ret)
 197                goto error_ret;
 198
 199        xfer.len = 9;
 200        xfer.tx_buf = &config->sin_tonep1[0];
 201
 202        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 203        if (ret)
 204                goto error_ret;
 205
 206        xfer.len = 9;
 207        xfer.tx_buf = &config->sin_tonep2[0];
 208
 209        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 210        if (ret)
 211                goto error_ret;
 212        xfer.len = 9;
 213        xfer.tx_buf = &config->sin_tonep3[0];
 214
 215        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 216        if (ret)
 217                goto error_ret;
 218
 219        xfer.len = 9;
 220        xfer.tx_buf = &config->sin_tonep4[0];
 221
 222        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 223        if (ret)
 224                goto error_ret;
 225
 226        xfer.len = 9;
 227        xfer.tx_buf = &config->sin_tonep5[0];
 228
 229        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 230        if (ret)
 231                goto error_ret;
 232
 233        xfer.len = 9;
 234        xfer.tx_buf = &config->sin_tonep6[0];
 235
 236        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 237        if (ret)
 238                goto error_ret;
 239
 240        xfer.len = 9;
 241        xfer.tx_buf = &config->sin_tonep7[0];
 242
 243        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 244        if (ret)
 245                goto error_ret;
 246error_ret:
 247        mutex_unlock(&st->lock);
 248
 249        return ret ? ret : len;
 250}
 251
 252static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0);
 253
 254static void ad9910_init(struct ad9910_state *st)
 255{
 256        struct spi_transfer xfer;
 257        int ret;
 258        u8 cfr[5];
 259
 260        cfr[0] = CFR1;
 261        cfr[1] = 0;
 262        cfr[2] = MANUAL_OSK | INVSIC | DDS_SINEOP;
 263        cfr[3] = AUTO_OSK | OSKEN | ACLR_PHA | ACLR_DIG | LOAD_LRR;
 264        cfr[4] = 0;
 265
 266        mutex_lock(&st->lock);
 267
 268        xfer.len = 5;
 269        xfer.tx_buf = &cfr;
 270
 271        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 272        if (ret)
 273                goto error_ret;
 274
 275        cfr[0] = CFR2;
 276        cfr[1] = ENA_AMP;
 277        cfr[2] = READ_FTW | DIGR_ENA | ITER_IOUPD;
 278        cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB;
 279        cfr[4] = PARA_ENA;
 280
 281        xfer.len = 5;
 282        xfer.tx_buf = &cfr;
 283
 284        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 285        if (ret)
 286                goto error_ret;
 287
 288        cfr[0] = CFR3;
 289        cfr[1] = PLL_ENA;
 290        cfr[2] = 0;
 291        cfr[3] = REFCLK_RST | REFCLK_BYP;
 292        cfr[4] = 0;
 293
 294        xfer.len = 5;
 295        xfer.tx_buf = &cfr;
 296
 297        ret = spi_sync_transfer(st->sdev, &xfer, 1);
 298        if (ret)
 299                goto error_ret;
 300
 301error_ret:
 302        mutex_unlock(&st->lock);
 303
 304
 305
 306}
 307
 308static struct attribute *ad9910_attributes[] = {
 309        &iio_dev_attr_dds.dev_attr.attr,
 310        NULL,
 311};
 312
 313static const struct attribute_group ad9910_attribute_group = {
 314        .attrs = ad9910_attributes,
 315};
 316
 317static const struct iio_info ad9910_info = {
 318        .attrs = &ad9910_attribute_group,
 319        .driver_module = THIS_MODULE,
 320};
 321
 322static int ad9910_probe(struct spi_device *spi)
 323{
 324        struct ad9910_state *st;
 325        struct iio_dev *idev;
 326        int ret = 0;
 327
 328        idev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 329        if (!idev)
 330                return -ENOMEM;
 331        spi_set_drvdata(spi, idev);
 332        st = iio_priv(idev);
 333        mutex_init(&st->lock);
 334        st->sdev = spi;
 335
 336        idev->dev.parent = &spi->dev;
 337        idev->info = &ad9910_info;
 338        idev->modes = INDIO_DIRECT_MODE;
 339
 340        ret = iio_device_register(idev);
 341        if (ret)
 342                return ret;
 343        spi->max_speed_hz = 2000000;
 344        spi->mode = SPI_MODE_3;
 345        spi->bits_per_word = 8;
 346        spi_setup(spi);
 347        ad9910_init(st);
 348        return 0;
 349}
 350
 351static int ad9910_remove(struct spi_device *spi)
 352{
 353        iio_device_unregister(spi_get_drvdata(spi));
 354
 355        return 0;
 356}
 357
 358static struct spi_driver ad9910_driver = {
 359        .driver = {
 360                .name = DRV_NAME,
 361                .owner = THIS_MODULE,
 362        },
 363        .probe = ad9910_probe,
 364        .remove = ad9910_remove,
 365};
 366module_spi_driver(ad9910_driver);
 367
 368MODULE_AUTHOR("Cliff Cai");
 369MODULE_DESCRIPTION("Analog Devices ad9910 driver");
 370MODULE_LICENSE("GPL v2");
 371MODULE_ALIAS("spi:" DRV_NAME);
 372