Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 228003
b: refs/heads/master
c: ffd7a62
h: refs/heads/master
i:
  228001: 0dcbcfd
  227999: c86ddd9
v: v3
  • Loading branch information
Graf Yang authored and Greg Kroah-Hartman committed Nov 9, 2010
1 parent 4e4df44 commit f97254d
Show file tree
Hide file tree
Showing 4 changed files with 320 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f46d9f154ac3001b90e75ca646400a13b499a49e
refs/heads/master: ffd7a62f0dffa92409dc769562a4997eb424a7d3
8 changes: 8 additions & 0 deletions trunk/drivers/staging/iio/resolver/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,11 @@ config AD2S90
help
Say yes here to build support for Analog Devices spi resolver
to digital converters, ad2s90, provides direct access via sysfs.

config AD2S120X
tristate "Analog Devices ad2s120x driver"
depends on SPI
help
Say yes here to build support for Analog Devices spi resolver
to digital converters, ad2s1200 and ad2s1205, provides direct access
via sysfs.
1 change: 1 addition & 0 deletions trunk/drivers/staging/iio/resolver/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
#

obj-$(CONFIG_AD2S90) += ad2s90.o
obj-$(CONFIG_AD2S120X) += ad2s120x.o
310 changes: 310 additions & 0 deletions trunk/drivers/staging/iio/resolver/ad2s120x.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
/*
* ad2s120x.c simple support for the ADI Resolver to Digital Converters: AD2S1200/1205
*
* Copyright (c) 2010-2010 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/delay.h>
#include <linux/gpio.h>

#include "../iio.h"
#include "../sysfs.h"

#define DRV_NAME "ad2s120x"

/* input pin sample and rdvel is controlled by driver */
#define AD2S120X_PN 2

/* input clock on serial interface */
#define AD2S120X_HZ 8192000
/* clock period in nano second */
#define AD2S120X_TSCLK (1000000000/AD2S120X_HZ)

struct ad2s120x_state {
struct mutex lock;
struct iio_dev *idev;
struct spi_device *sdev;
unsigned short sample;
unsigned short rdvel;
u8 rx[2];
u8 tx[2];
};

static ssize_t ad2s120x_show_pos_vel(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct spi_message msg;
struct spi_transfer xfer;
int ret = 0;
ssize_t len = 0;
u16 pos;
s16 vel;
u8 status;
struct iio_dev *idev = dev_get_drvdata(dev);
struct ad2s120x_state *st = idev->dev_data;

xfer.len = 1;
xfer.tx_buf = st->tx;
xfer.rx_buf = st->rx;
mutex_lock(&st->lock);

gpio_set_value(st->sample, 0);
/* delay (6 * AD2S120X_TSCLK + 20) nano seconds */
udelay(1);
gpio_set_value(st->sample, 1);

spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
ret = spi_sync(st->sdev, &msg);
if (ret)
goto error_ret;
status = st->rx[1];
pos = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
len = sprintf(buf, "%d %c%c%c%c ", pos,
(status & 0x8) ? 'P' : 'V',
(status & 0x4) ? 'd' : '_',
(status & 0x2) ? 'l' : '_',
(status & 0x1) ? '1' : '0');

/* delay 18 ns */
/* ndelay(18); */

gpio_set_value(st->rdvel, 0);
/* ndelay(5);*/

spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
ret = spi_sync(st->sdev, &msg);
if (ret)
goto error_ret;
status = st->rx[1];
vel = (st->rx[0] & 0x80) ? 0xf000 : 0;
vel |= (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
len += sprintf(buf + len, "%d %c%c%c%c\n", vel,
(status & 0x8) ? 'P' : 'V',
(status & 0x4) ? 'd' : '_',
(status & 0x2) ? 'l' : '_',
(status & 0x1) ? '1' : '0');
error_ret:
gpio_set_value(st->rdvel, 1);
/* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */
udelay(1);
mutex_unlock(&st->lock);

return ret ? ret : len;
}

static ssize_t ad2s120x_show_pos(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct spi_message msg;
struct spi_transfer xfer;
int ret = 0;
ssize_t len = 0;
u16 pos;
u8 status;
struct iio_dev *idev = dev_get_drvdata(dev);
struct ad2s120x_state *st = idev->dev_data;

xfer.len = 1;
xfer.tx_buf = st->tx;
xfer.rx_buf = st->rx;
mutex_lock(&st->lock);

gpio_set_value(st->sample, 0);
/* delay (6 * AD2S120X_TSCLK + 20) nano seconds */
udelay(1);
gpio_set_value(st->sample, 1);
gpio_set_value(st->rdvel, 1);

spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
ret = spi_sync(st->sdev, &msg);
if (ret)
goto error_ret;
status = st->rx[1];
pos = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
len = sprintf(buf, "%d %c%c%c%c ", pos,
(status & 0x8) ? 'P' : 'V',
(status & 0x4) ? 'd' : '_',
(status & 0x2) ? 'l' : '_',
(status & 0x1) ? '1' : '0');
error_ret:
/* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */
udelay(1);
mutex_unlock(&st->lock);

return ret ? ret : len;
}

static ssize_t ad2s120x_show_vel(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct spi_message msg;
struct spi_transfer xfer;
int ret = 0;
ssize_t len = 0;
s16 vel;
u8 status;
struct iio_dev *idev = dev_get_drvdata(dev);
struct ad2s120x_state *st = idev->dev_data;

xfer.len = 1;
xfer.tx_buf = st->tx;
xfer.rx_buf = st->rx;
mutex_lock(&st->lock);

gpio_set_value(st->sample, 0);
/* delay (6 * AD2S120X_TSCLK + 20) nano seconds */
udelay(1);
gpio_set_value(st->sample, 1);

gpio_set_value(st->rdvel, 0);
/* ndelay(5);*/

spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
ret = spi_sync(st->sdev, &msg);
if (ret)
goto error_ret;
status = st->rx[1];
vel = (st->rx[0] & 0x80) ? 0xf000 : 0;
vel |= (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
len += sprintf(buf + len, "%d %c%c%c%c\n", vel,
(status & 0x8) ? 'P' : 'V',
(status & 0x4) ? 'd' : '_',
(status & 0x2) ? 'l' : '_',
(status & 0x1) ? '1' : '0');
error_ret:
gpio_set_value(st->rdvel, 1);
/* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */
udelay(1);
mutex_unlock(&st->lock);

return ret ? ret : len;
}

static IIO_CONST_ATTR(description,
"12-Bit R/D Converter with Reference Oscillator");
static IIO_DEVICE_ATTR(pos_vel, S_IRUGO, ad2s120x_show_pos_vel, NULL, 0);
static IIO_DEVICE_ATTR(pos, S_IRUGO, ad2s120x_show_pos, NULL, 0);
static IIO_DEVICE_ATTR(vel, S_IRUGO, ad2s120x_show_vel, NULL, 0);

static struct attribute *ad2s120x_attributes[] = {
&iio_const_attr_description.dev_attr.attr,
&iio_dev_attr_pos_vel.dev_attr.attr,
&iio_dev_attr_pos.dev_attr.attr,
&iio_dev_attr_vel.dev_attr.attr,
NULL,
};

static const struct attribute_group ad2s120x_attribute_group = {
.name = DRV_NAME,
.attrs = ad2s120x_attributes,
};

static int __devinit ad2s120x_probe(struct spi_device *spi)
{
struct ad2s120x_state *st;
int pn, ret = 0;
unsigned short *pins = spi->dev.platform_data;

for (pn = 0; pn < AD2S120X_PN; pn++) {
if (gpio_request(pins[pn], DRV_NAME)) {
pr_err("%s: request gpio pin %d failed\n",
DRV_NAME, pins[pn]);
goto error_ret;
}
gpio_direction_output(pins[pn], 1);
}

st = kzalloc(sizeof(*st), GFP_KERNEL);
if (st == NULL) {
ret = -ENOMEM;
goto error_ret;
}
spi_set_drvdata(spi, st);

mutex_init(&st->lock);
st->sdev = spi;
st->sample = pins[0];
st->rdvel = pins[1];

st->idev = iio_allocate_device();
if (st->idev == NULL) {
ret = -ENOMEM;
goto error_free_st;
}
st->idev->dev.parent = &spi->dev;
st->idev->num_interrupt_lines = 0;
st->idev->event_attrs = NULL;

st->idev->attrs = &ad2s120x_attribute_group;
st->idev->dev_data = (void *)(st);
st->idev->driver_module = THIS_MODULE;
st->idev->modes = INDIO_DIRECT_MODE;

ret = iio_device_register(st->idev);
if (ret)
goto error_free_dev;

spi->max_speed_hz = AD2S120X_HZ;
spi->mode = SPI_MODE_3;
spi_setup(spi);

return 0;

error_free_dev:
iio_free_device(st->idev);
error_free_st:
kfree(st);
error_ret:
for (--pn; pn >= 0; pn--)
gpio_free(pins[pn]);
return ret;
}

static int __devexit ad2s120x_remove(struct spi_device *spi)
{
struct ad2s120x_state *st = spi_get_drvdata(spi);

iio_device_unregister(st->idev);
kfree(st);

return 0;
}

static struct spi_driver ad2s120x_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
.probe = ad2s120x_probe,
.remove = __devexit_p(ad2s120x_remove),
};

static __init int ad2s120x_spi_init(void)
{
return spi_register_driver(&ad2s120x_driver);
}
module_init(ad2s120x_spi_init);

static __exit void ad2s120x_spi_exit(void)
{
spi_unregister_driver(&ad2s120x_driver);
}
module_exit(ad2s120x_spi_exit);

MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver");
MODULE_LICENSE("GPL v2");

0 comments on commit f97254d

Please sign in to comment.