~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/staging/iio/dac/ad5504.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * AD5504, AD5501 High Voltage Digital to Analog Converter
 
3
 *
 
4
 * Copyright 2011 Analog Devices Inc.
 
5
 *
 
6
 * Licensed under the GPL-2.
 
7
 */
 
8
 
 
9
#include <linux/interrupt.h>
 
10
#include <linux/fs.h>
 
11
#include <linux/device.h>
 
12
#include <linux/kernel.h>
 
13
#include <linux/spi/spi.h>
 
14
#include <linux/slab.h>
 
15
#include <linux/sysfs.h>
 
16
#include <linux/regulator/consumer.h>
 
17
#include <linux/module.h>
 
18
 
 
19
#include "../iio.h"
 
20
#include "../sysfs.h"
 
21
#include "dac.h"
 
22
#include "ad5504.h"
 
23
 
 
24
static int ad5504_spi_write(struct spi_device *spi, u8 addr, u16 val)
 
25
{
 
26
        u16 tmp = cpu_to_be16(AD5504_CMD_WRITE |
 
27
                              AD5504_ADDR(addr) |
 
28
                              (val & AD5504_RES_MASK));
 
29
 
 
30
        return spi_write(spi, (u8 *)&tmp, 2);
 
31
}
 
32
 
 
33
static int ad5504_spi_read(struct spi_device *spi, u8 addr, u16 *val)
 
34
{
 
35
        u16 tmp = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr));
 
36
        int ret;
 
37
        struct spi_transfer     t = {
 
38
                        .tx_buf         = &tmp,
 
39
                        .rx_buf         = val,
 
40
                        .len            = 2,
 
41
                };
 
42
        struct spi_message      m;
 
43
 
 
44
        spi_message_init(&m);
 
45
        spi_message_add_tail(&t, &m);
 
46
        ret = spi_sync(spi, &m);
 
47
 
 
48
        *val = be16_to_cpu(*val) & AD5504_RES_MASK;
 
49
 
 
50
        return ret;
 
51
}
 
52
 
 
53
static ssize_t ad5504_write_dac(struct device *dev,
 
54
                                 struct device_attribute *attr,
 
55
                                 const char *buf, size_t len)
 
56
{
 
57
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
58
        struct ad5504_state *st = iio_priv(indio_dev);
 
59
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
60
        long readin;
 
61
        int ret;
 
62
 
 
63
        ret = strict_strtol(buf, 10, &readin);
 
64
        if (ret)
 
65
                return ret;
 
66
 
 
67
        ret = ad5504_spi_write(st->spi, this_attr->address, readin);
 
68
        return ret ? ret : len;
 
69
}
 
70
 
 
71
static ssize_t ad5504_read_dac(struct device *dev,
 
72
                                           struct device_attribute *attr,
 
73
                                           char *buf)
 
74
{
 
75
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
76
        struct ad5504_state *st = iio_priv(indio_dev);
 
77
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
78
        int ret;
 
79
        u16 val;
 
80
 
 
81
        ret = ad5504_spi_read(st->spi, this_attr->address, &val);
 
82
        if (ret)
 
83
                return ret;
 
84
 
 
85
        return sprintf(buf, "%d\n", val);
 
86
}
 
87
 
 
88
static ssize_t ad5504_read_powerdown_mode(struct device *dev,
 
89
                                      struct device_attribute *attr, char *buf)
 
90
{
 
91
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
92
        struct ad5504_state *st = iio_priv(indio_dev);
 
93
 
 
94
        const char mode[][14] = {"20kohm_to_gnd", "three_state"};
 
95
 
 
96
        return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
 
97
}
 
98
 
 
99
static ssize_t ad5504_write_powerdown_mode(struct device *dev,
 
100
                                       struct device_attribute *attr,
 
101
                                       const char *buf, size_t len)
 
102
{
 
103
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
104
        struct ad5504_state *st = iio_priv(indio_dev);
 
105
        int ret;
 
106
 
 
107
        if (sysfs_streq(buf, "20kohm_to_gnd"))
 
108
                st->pwr_down_mode = AD5504_DAC_PWRDN_20K;
 
109
        else if (sysfs_streq(buf, "three_state"))
 
110
                st->pwr_down_mode = AD5504_DAC_PWRDN_3STATE;
 
111
        else
 
112
                ret = -EINVAL;
 
113
 
 
114
        return ret ? ret : len;
 
115
}
 
116
 
 
117
static ssize_t ad5504_read_dac_powerdown(struct device *dev,
 
118
                                           struct device_attribute *attr,
 
119
                                           char *buf)
 
120
{
 
121
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
122
        struct ad5504_state *st = iio_priv(indio_dev);
 
123
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
124
 
 
125
        return sprintf(buf, "%d\n",
 
126
                        !(st->pwr_down_mask & (1 << this_attr->address)));
 
127
}
 
128
 
 
129
static ssize_t ad5504_write_dac_powerdown(struct device *dev,
 
130
                                            struct device_attribute *attr,
 
131
                                            const char *buf, size_t len)
 
132
{
 
133
        long readin;
 
134
        int ret;
 
135
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
136
        struct ad5504_state *st = iio_priv(indio_dev);
 
137
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
138
 
 
139
        ret = strict_strtol(buf, 10, &readin);
 
140
        if (ret)
 
141
                return ret;
 
142
 
 
143
        if (readin == 0)
 
144
                st->pwr_down_mask |= (1 << this_attr->address);
 
145
        else if (readin == 1)
 
146
                st->pwr_down_mask &= ~(1 << this_attr->address);
 
147
        else
 
148
                ret = -EINVAL;
 
149
 
 
150
        ret = ad5504_spi_write(st->spi, AD5504_ADDR_CTRL,
 
151
                                AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) |
 
152
                                AD5504_DAC_PWR(st->pwr_down_mask));
 
153
 
 
154
        /* writes to the CTRL register must be followed by a NOOP */
 
155
        ad5504_spi_write(st->spi, AD5504_ADDR_NOOP, 0);
 
156
 
 
157
        return ret ? ret : len;
 
158
}
 
159
 
 
160
static ssize_t ad5504_show_scale(struct device *dev,
 
161
                                struct device_attribute *attr,
 
162
                                char *buf)
 
163
{
 
164
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
165
        struct ad5504_state *st = iio_priv(indio_dev);
 
166
        /* Corresponds to Vref / 2^(bits) */
 
167
        unsigned int scale_uv = (st->vref_mv * 1000) >> AD5505_BITS;
 
168
 
 
169
        return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
 
170
}
 
171
static IIO_DEVICE_ATTR(out_voltage_scale, S_IRUGO, ad5504_show_scale, NULL, 0);
 
172
 
 
173
#define IIO_DEV_ATTR_OUT_RW_RAW(_num, _show, _store, _addr)             \
 
174
        IIO_DEVICE_ATTR(out_voltage##_num##_raw,                        \
 
175
                        S_IRUGO | S_IWUSR, _show, _store, _addr)
 
176
 
 
177
static IIO_DEV_ATTR_OUT_RW_RAW(0, ad5504_read_dac,
 
178
        ad5504_write_dac, AD5504_ADDR_DAC0);
 
179
static IIO_DEV_ATTR_OUT_RW_RAW(1, ad5504_read_dac,
 
180
        ad5504_write_dac, AD5504_ADDR_DAC1);
 
181
static IIO_DEV_ATTR_OUT_RW_RAW(2, ad5504_read_dac,
 
182
        ad5504_write_dac, AD5504_ADDR_DAC2);
 
183
static IIO_DEV_ATTR_OUT_RW_RAW(3, ad5504_read_dac,
 
184
        ad5504_write_dac, AD5504_ADDR_DAC3);
 
185
 
 
186
static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO |
 
187
                        S_IWUSR, ad5504_read_powerdown_mode,
 
188
                        ad5504_write_powerdown_mode, 0);
 
189
 
 
190
static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
 
191
                        "20kohm_to_gnd three_state");
 
192
 
 
193
#define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr)          \
 
194
        IIO_DEVICE_ATTR(out_voltage##_num##_powerdown,                  \
 
195
                        S_IRUGO | S_IWUSR, _show, _store, _addr)
 
196
static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5504_read_dac_powerdown,
 
197
                                   ad5504_write_dac_powerdown, 0);
 
198
static IIO_DEV_ATTR_DAC_POWERDOWN(1, ad5504_read_dac_powerdown,
 
199
                                   ad5504_write_dac_powerdown, 1);
 
200
static IIO_DEV_ATTR_DAC_POWERDOWN(2, ad5504_read_dac_powerdown,
 
201
                                   ad5504_write_dac_powerdown, 2);
 
202
static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5504_read_dac_powerdown,
 
203
                                   ad5504_write_dac_powerdown, 3);
 
204
 
 
205
static struct attribute *ad5504_attributes[] = {
 
206
        &iio_dev_attr_out_voltage0_raw.dev_attr.attr,
 
207
        &iio_dev_attr_out_voltage1_raw.dev_attr.attr,
 
208
        &iio_dev_attr_out_voltage2_raw.dev_attr.attr,
 
209
        &iio_dev_attr_out_voltage3_raw.dev_attr.attr,
 
210
        &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
 
211
        &iio_dev_attr_out_voltage1_powerdown.dev_attr.attr,
 
212
        &iio_dev_attr_out_voltage2_powerdown.dev_attr.attr,
 
213
        &iio_dev_attr_out_voltage3_powerdown.dev_attr.attr,
 
214
        &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
 
215
        &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
 
216
        &iio_dev_attr_out_voltage_scale.dev_attr.attr,
 
217
        NULL,
 
218
};
 
219
 
 
220
static const struct attribute_group ad5504_attribute_group = {
 
221
        .attrs = ad5504_attributes,
 
222
};
 
223
 
 
224
static struct attribute *ad5501_attributes[] = {
 
225
        &iio_dev_attr_out_voltage0_raw.dev_attr.attr,
 
226
        &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
 
227
        &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
 
228
        &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
 
229
        &iio_dev_attr_out_voltage_scale.dev_attr.attr,
 
230
        NULL,
 
231
};
 
232
 
 
233
static const struct attribute_group ad5501_attribute_group = {
 
234
        .attrs = ad5501_attributes,
 
235
};
 
236
 
 
237
static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000");
 
238
static IIO_CONST_ATTR(temp0_thresh_rising_en, "1");
 
239
 
 
240
static struct attribute *ad5504_ev_attributes[] = {
 
241
        &iio_const_attr_temp0_thresh_rising_value.dev_attr.attr,
 
242
        &iio_const_attr_temp0_thresh_rising_en.dev_attr.attr,
 
243
        NULL,
 
244
};
 
245
 
 
246
static struct attribute_group ad5504_ev_attribute_group = {
 
247
        .attrs = ad5504_ev_attributes,
 
248
        .name = "events",
 
249
};
 
250
 
 
251
static irqreturn_t ad5504_event_handler(int irq, void *private)
 
252
{
 
253
        iio_push_event(private,
 
254
                       IIO_UNMOD_EVENT_CODE(IIO_TEMP,
 
255
                                            0,
 
256
                                            IIO_EV_TYPE_THRESH,
 
257
                                            IIO_EV_DIR_RISING),
 
258
                       iio_get_time_ns());
 
259
 
 
260
        return IRQ_HANDLED;
 
261
}
 
262
 
 
263
static const struct iio_info ad5504_info = {
 
264
        .attrs = &ad5504_attribute_group,
 
265
        .event_attrs = &ad5504_ev_attribute_group,
 
266
        .driver_module = THIS_MODULE,
 
267
};
 
268
 
 
269
static const struct iio_info ad5501_info = {
 
270
        .attrs = &ad5501_attribute_group,
 
271
        .event_attrs = &ad5504_ev_attribute_group,
 
272
        .driver_module = THIS_MODULE,
 
273
};
 
274
 
 
275
static int __devinit ad5504_probe(struct spi_device *spi)
 
276
{
 
277
        struct ad5504_platform_data *pdata = spi->dev.platform_data;
 
278
        struct iio_dev *indio_dev;
 
279
        struct ad5504_state *st;
 
280
        struct regulator *reg;
 
281
        int ret, voltage_uv = 0;
 
282
 
 
283
        indio_dev = iio_allocate_device(sizeof(*st));
 
284
        if (indio_dev == NULL) {
 
285
                ret = -ENOMEM;
 
286
                goto error_ret;
 
287
        }
 
288
        reg = regulator_get(&spi->dev, "vcc");
 
289
        if (!IS_ERR(reg)) {
 
290
                ret = regulator_enable(reg);
 
291
                if (ret)
 
292
                        goto error_put_reg;
 
293
 
 
294
                voltage_uv = regulator_get_voltage(reg);
 
295
        }
 
296
 
 
297
        spi_set_drvdata(spi, indio_dev);
 
298
        st = iio_priv(indio_dev);
 
299
        if (voltage_uv)
 
300
                st->vref_mv = voltage_uv / 1000;
 
301
        else if (pdata)
 
302
                st->vref_mv = pdata->vref_mv;
 
303
        else
 
304
                dev_warn(&spi->dev, "reference voltage unspecified\n");
 
305
 
 
306
        st->reg = reg;
 
307
        st->spi = spi;
 
308
        indio_dev->dev.parent = &spi->dev;
 
309
        indio_dev->name = spi_get_device_id(st->spi)->name;
 
310
        if (spi_get_device_id(st->spi)->driver_data == ID_AD5501)
 
311
                indio_dev->info = &ad5501_info;
 
312
        else
 
313
                indio_dev->info = &ad5504_info;
 
314
        indio_dev->modes = INDIO_DIRECT_MODE;
 
315
 
 
316
        if (spi->irq) {
 
317
                ret = request_threaded_irq(spi->irq,
 
318
                                           NULL,
 
319
                                           &ad5504_event_handler,
 
320
                                           IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 
321
                                           spi_get_device_id(st->spi)->name,
 
322
                                           indio_dev);
 
323
                if (ret)
 
324
                        goto error_disable_reg;
 
325
        }
 
326
 
 
327
        ret = iio_device_register(indio_dev);
 
328
        if (ret)
 
329
                goto error_free_irq;
 
330
 
 
331
        return 0;
 
332
 
 
333
error_free_irq:
 
334
        free_irq(spi->irq, indio_dev);
 
335
error_disable_reg:
 
336
        if (!IS_ERR(reg))
 
337
                regulator_disable(reg);
 
338
error_put_reg:
 
339
        if (!IS_ERR(reg))
 
340
                regulator_put(reg);
 
341
 
 
342
        iio_free_device(indio_dev);
 
343
error_ret:
 
344
        return ret;
 
345
}
 
346
 
 
347
static int __devexit ad5504_remove(struct spi_device *spi)
 
348
{
 
349
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
350
        struct ad5504_state *st = iio_priv(indio_dev);
 
351
 
 
352
        iio_device_unregister(indio_dev);
 
353
        if (spi->irq)
 
354
                free_irq(spi->irq, indio_dev);
 
355
 
 
356
        if (!IS_ERR(st->reg)) {
 
357
                regulator_disable(st->reg);
 
358
                regulator_put(st->reg);
 
359
        }
 
360
        iio_free_device(indio_dev);
 
361
 
 
362
        return 0;
 
363
}
 
364
 
 
365
static const struct spi_device_id ad5504_id[] = {
 
366
        {"ad5504", ID_AD5504},
 
367
        {"ad5501", ID_AD5501},
 
368
        {}
 
369
};
 
370
 
 
371
static struct spi_driver ad5504_driver = {
 
372
        .driver = {
 
373
                   .name = "ad5504",
 
374
                   .owner = THIS_MODULE,
 
375
                   },
 
376
        .probe = ad5504_probe,
 
377
        .remove = __devexit_p(ad5504_remove),
 
378
        .id_table = ad5504_id,
 
379
};
 
380
 
 
381
static __init int ad5504_spi_init(void)
 
382
{
 
383
        return spi_register_driver(&ad5504_driver);
 
384
}
 
385
module_init(ad5504_spi_init);
 
386
 
 
387
static __exit void ad5504_spi_exit(void)
 
388
{
 
389
        spi_unregister_driver(&ad5504_driver);
 
390
}
 
391
module_exit(ad5504_spi_exit);
 
392
 
 
393
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 
394
MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC");
 
395
MODULE_LICENSE("GPL v2");